Merge ref '139651428d' from rust-lang/rust
Pull recent changes from https://github.com/rust-lang/rust via Josh.
Upstream ref: rust-lang/rust@139651428d
Filtered ref: rust-lang/rust-analyzer@3efb0c2db4
Upstream diff: ba284f468c...139651428d
This merge was created using https://github.com/rust-lang/josh-sync.
This commit is contained in:
commit
1fb6fc177f
2387 changed files with 54065 additions and 45966 deletions
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
|
|
@ -165,9 +165,6 @@ 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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 in the [Standard library developers Guide][std-dev-guide], commonly known as the [std-dev-guide].
|
||||
standard library is in the [Standard library developers Guide][std-dev-guide], commonly known as the [std-dev-guide].
|
||||
|
||||
## Making changes to subtrees and submodules
|
||||
|
||||
|
|
|
|||
115
Cargo.lock
115
Cargo.lock
|
|
@ -184,9 +184,9 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
|||
|
||||
[[package]]
|
||||
name = "askama"
|
||||
version = "0.15.2"
|
||||
version = "0.15.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03341eae1125472b0672fbf35cc9aa7b74cd8e0c3d02f02c28a04678f12aaa7a"
|
||||
checksum = "08e1676b346cadfec169374f949d7490fd80a24193d37d2afce0c047cf695e57"
|
||||
dependencies = [
|
||||
"askama_macros",
|
||||
"itoa",
|
||||
|
|
@ -197,9 +197,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "askama_derive"
|
||||
version = "0.15.2"
|
||||
version = "0.15.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "461bd78f3da90b5e44eee4272cfb1c4832aa3dcdb6c370aedd3eb253d2b9e3ca"
|
||||
checksum = "7661ff56517787343f376f75db037426facd7c8d3049cef8911f1e75016f3a37"
|
||||
dependencies = [
|
||||
"askama_parser",
|
||||
"basic-toml",
|
||||
|
|
@ -214,18 +214,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "askama_macros"
|
||||
version = "0.15.2"
|
||||
version = "0.15.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba49fb22ee3074574b8510abd9495d4f0bb9b8f87e8e45ee31e2cee508f7a8e5"
|
||||
checksum = "713ee4dbfd1eb719c2dab859465b01fa1d21cb566684614a713a6b7a99a4e47b"
|
||||
dependencies = [
|
||||
"askama_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_parser"
|
||||
version = "0.15.2"
|
||||
version = "0.15.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e33eb7484958aaa1f27e9adb556f5d557331cd891bdbb33781bc1f9550b6f6e"
|
||||
checksum = "1d62d674238a526418b30c0def480d5beadb9d8964e7f38d635b03bf639c704c"
|
||||
dependencies = [
|
||||
"rustc-hash 2.1.1",
|
||||
"serde",
|
||||
|
|
@ -580,9 +580,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.51"
|
||||
version = "4.5.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5"
|
||||
checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
|
@ -600,9 +600,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.51"
|
||||
version = "4.5.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a"
|
||||
checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
|
|
@ -1298,9 +1298,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ena"
|
||||
version = "0.14.3"
|
||||
version = "0.14.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5"
|
||||
checksum = "eabffdaee24bd1bf95c5ef7cec31260444317e72ea56c4c91750e8b7ee58d5f1"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
|
@ -3490,7 +3490,6 @@ dependencies = [
|
|||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
|
|
@ -3515,7 +3514,6 @@ dependencies = [
|
|||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_macros",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
|
|
@ -3541,9 +3539,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",
|
||||
|
|
@ -3574,7 +3572,6 @@ dependencies = [
|
|||
"rustc_abi",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_graphviz",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
|
|
@ -3602,7 +3599,6 @@ dependencies = [
|
|||
"rustc_errors",
|
||||
"rustc_expand",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_lexer",
|
||||
|
|
@ -3636,7 +3632,6 @@ dependencies = [
|
|||
"rustc_codegen_ssa",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_fs_util",
|
||||
"rustc_hashes",
|
||||
"rustc_hir",
|
||||
|
|
@ -3674,7 +3669,6 @@ dependencies = [
|
|||
"rustc_attr_parsing",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_fs_util",
|
||||
"rustc_hashes",
|
||||
"rustc_hir",
|
||||
|
|
@ -3684,7 +3678,6 @@ dependencies = [
|
|||
"rustc_macros",
|
||||
"rustc_metadata",
|
||||
"rustc_middle",
|
||||
"rustc_query_system",
|
||||
"rustc_serialize",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
|
|
@ -3694,7 +3687,6 @@ dependencies = [
|
|||
"serde_json",
|
||||
"smallvec",
|
||||
"tempfile",
|
||||
"thin-vec",
|
||||
"thorin-dwp",
|
||||
"tracing",
|
||||
"wasm-encoder 0.219.2",
|
||||
|
|
@ -3711,7 +3703,6 @@ dependencies = [
|
|||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_infer",
|
||||
|
|
@ -3777,25 +3768,16 @@ dependencies = [
|
|||
"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",
|
||||
|
|
@ -3804,21 +3786,13 @@ dependencies = [
|
|||
"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",
|
||||
|
|
@ -3862,7 +3836,6 @@ dependencies = [
|
|||
"rustc_data_structures",
|
||||
"rustc_error_codes",
|
||||
"rustc_error_messages",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hashes",
|
||||
"rustc_index",
|
||||
"rustc_lint_defs",
|
||||
|
|
@ -3887,7 +3860,6 @@ dependencies = [
|
|||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_lexer",
|
||||
"rustc_lint_defs",
|
||||
|
|
@ -3915,19 +3887,6 @@ 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"
|
||||
|
|
@ -3982,7 +3941,6 @@ dependencies = [
|
|||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_infer",
|
||||
|
|
@ -4029,7 +3987,6 @@ dependencies = [
|
|||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_hir_analysis",
|
||||
"rustc_hir_pretty",
|
||||
|
|
@ -4051,10 +4008,8 @@ 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",
|
||||
|
|
@ -4064,7 +4019,6 @@ dependencies = [
|
|||
"rustc_serialize",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"thin-vec",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
|
|
@ -4093,7 +4047,6 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
|
|
@ -4124,7 +4077,6 @@ dependencies = [
|
|||
"rustc_errors",
|
||||
"rustc_expand",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_fs_util",
|
||||
"rustc_hir",
|
||||
"rustc_hir_analysis",
|
||||
|
|
@ -4141,7 +4093,6 @@ dependencies = [
|
|||
"rustc_passes",
|
||||
"rustc_privacy",
|
||||
"rustc_query_impl",
|
||||
"rustc_query_system",
|
||||
"rustc_resolve",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
|
|
@ -4177,7 +4128,6 @@ dependencies = [
|
|||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_infer",
|
||||
|
|
@ -4229,6 +4179,8 @@ dependencies = [
|
|||
name = "rustc_macros"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"fluent-bundle",
|
||||
"fluent-syntax",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.110",
|
||||
|
|
@ -4250,7 +4202,6 @@ dependencies = [
|
|||
"rustc_errors",
|
||||
"rustc_expand",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_fs_util",
|
||||
"rustc_hir",
|
||||
"rustc_hir_pretty",
|
||||
|
|
@ -4274,6 +4225,7 @@ dependencies = [
|
|||
"bitflags",
|
||||
"either",
|
||||
"gsgdt",
|
||||
"parking_lot",
|
||||
"polonius-engine",
|
||||
"rustc_abi",
|
||||
"rustc_apfloat",
|
||||
|
|
@ -4284,7 +4236,6 @@ dependencies = [
|
|||
"rustc_error_messages",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_graphviz",
|
||||
"rustc_hashes",
|
||||
"rustc_hir",
|
||||
|
|
@ -4315,7 +4266,6 @@ dependencies = [
|
|||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_infer",
|
||||
|
|
@ -4336,11 +4286,10 @@ 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",
|
||||
|
|
@ -4354,7 +4303,6 @@ name = "rustc_mir_transform"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"either",
|
||||
"hashbrown 0.16.1",
|
||||
"itertools",
|
||||
"rustc_abi",
|
||||
"rustc_arena",
|
||||
|
|
@ -4362,7 +4310,6 @@ dependencies = [
|
|||
"rustc_const_eval",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_infer",
|
||||
|
|
@ -4384,7 +4331,6 @@ dependencies = [
|
|||
"rustc_abi",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
|
|
@ -4421,7 +4367,6 @@ dependencies = [
|
|||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_index",
|
||||
"rustc_lexer",
|
||||
"rustc_macros",
|
||||
|
|
@ -4454,7 +4399,6 @@ dependencies = [
|
|||
"rustc_errors",
|
||||
"rustc_expand",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
|
|
@ -4477,7 +4421,6 @@ dependencies = [
|
|||
"rustc_arena",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
|
|
@ -4497,7 +4440,6 @@ dependencies = [
|
|||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_macros",
|
||||
"rustc_middle",
|
||||
|
|
@ -4550,14 +4492,19 @@ name = "rustc_query_impl"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"measureme",
|
||||
"rustc_abi",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_hashes",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
"rustc_middle",
|
||||
"rustc_query_system",
|
||||
"rustc_serialize",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_thread_pool",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
|
|
@ -4565,24 +4512,17 @@ dependencies = [
|
|||
name = "rustc_query_system"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"hashbrown 0.16.1",
|
||||
"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_serialize",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_thread_pool",
|
||||
"smallvec",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4600,13 +4540,11 @@ 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",
|
||||
|
|
@ -4654,7 +4592,6 @@ dependencies = [
|
|||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_fs_util",
|
||||
"rustc_hashes",
|
||||
"rustc_hir",
|
||||
|
|
@ -4761,7 +4698,6 @@ dependencies = [
|
|||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_infer",
|
||||
"rustc_macros",
|
||||
|
|
@ -4810,7 +4746,6 @@ dependencies = [
|
|||
"rustc_abi",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hashes",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
|
|
@ -5623,7 +5558,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"build_helper",
|
||||
"cargo_metadata 0.21.0",
|
||||
"fluent-syntax",
|
||||
"clap",
|
||||
"globset",
|
||||
"ignore",
|
||||
"miropt-test-tools",
|
||||
|
|
|
|||
|
|
@ -233,7 +233,7 @@ itself back on after some time).
|
|||
|
||||
### MSVC
|
||||
|
||||
MSVC builds of Rust additionally requires an installation of:
|
||||
MSVC builds of Rust additionally require 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.
|
||||
|
|
|
|||
17
RELEASES.md
17
RELEASES.md
|
|
@ -1,3 +1,12 @@
|
|||
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)
|
||||
==========================
|
||||
|
||||
|
|
@ -1546,7 +1555,7 @@ Compatibility Notes
|
|||
- [Check well-formedness of the source type's signature in fn pointer casts.](https://github.com/rust-lang/rust/pull/129021) This partly closes a soundness hole that comes when casting a function item to function pointer
|
||||
- [Use equality instead of subtyping when resolving type dependent paths.](https://github.com/rust-lang/rust/pull/129073)
|
||||
- Linking on macOS now correctly includes Rust's default deployment target. Due to a linker bug, you might have to pass `MACOSX_DEPLOYMENT_TARGET` or fix your `#[link]` attributes to point to the correct frameworks. See <https://github.com/rust-lang/rust/pull/129369>.
|
||||
- [Rust will now correctly raise an error for `repr(Rust)` written on non-`struct`/`enum`/`union` items, since it previous did not have any effect.](https://github.com/rust-lang/rust/pull/129422)
|
||||
- [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)
|
||||
- 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.
|
||||
|
|
@ -1722,7 +1731,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 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.
|
||||
- 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.
|
||||
- [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
|
||||
|
|
@ -1872,7 +1881,7 @@ These changes do not affect any public interfaces of Rust, but they represent
|
|||
significant improvements to the performance or internals of rustc and related
|
||||
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)
|
||||
===========================
|
||||
|
|
@ -4510,7 +4519,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 results in `0` rather than a panic.
|
||||
errors will now result 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].
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
// 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
|
||||
|
|
@ -38,6 +40,6 @@
|
|||
#[cfg(feature = "jemalloc")]
|
||||
use tikv_jemalloc_sys as _;
|
||||
|
||||
fn main() {
|
||||
fn main() -> ExitCode {
|
||||
rustc_driver::main()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ impl Reg {
|
|||
|
||||
reg_ctor!(f32, Float, 32);
|
||||
reg_ctor!(f64, Float, 64);
|
||||
reg_ctor!(f128, Float, 128);
|
||||
}
|
||||
|
||||
impl Reg {
|
||||
|
|
|
|||
|
|
@ -290,7 +290,19 @@ 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>(mut self, cx: &C) -> bool
|
||||
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
|
||||
where
|
||||
Ty: TyAbiInterface<'a, C> + Copy,
|
||||
{
|
||||
|
|
@ -300,7 +312,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
|
|||
self = field;
|
||||
}
|
||||
|
||||
Ty::is_pass_indirectly_in_non_rustic_abis_flag_set(self)
|
||||
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,7 +13,6 @@
|
|||
#![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)]
|
||||
|
|
@ -26,7 +25,7 @@ use std::cell::{Cell, RefCell};
|
|||
use std::marker::PhantomData;
|
||||
use std::mem::{self, MaybeUninit};
|
||||
use std::ptr::{self, NonNull};
|
||||
use std::{cmp, intrinsics, slice};
|
||||
use std::{cmp, hint, slice};
|
||||
|
||||
use smallvec::SmallVec;
|
||||
|
||||
|
|
@ -172,8 +171,22 @@ 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]
|
||||
fn alloc_raw_slice(&self, len: usize) -> *mut T {
|
||||
unsafe fn alloc_raw_slice(&self, len: usize) -> *mut T {
|
||||
assert!(size_of::<T>() != 0);
|
||||
assert!(len != 0);
|
||||
|
||||
|
|
@ -208,7 +221,7 @@ impl<T> TypedArena<T> {
|
|||
&self,
|
||||
iter: impl IntoIterator<Item = Result<T, E>>,
|
||||
) -> Result<&mut [T], E> {
|
||||
// Despite the similarlty with `DroplessArena`, we cannot reuse their fast case. The reason
|
||||
// Despite the similarity 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.
|
||||
//
|
||||
|
|
@ -229,9 +242,15 @@ impl<T> TypedArena<T> {
|
|||
}
|
||||
// Move the content to the arena by copying and then forgetting it.
|
||||
let len = vec.len();
|
||||
let start_ptr = self.alloc_raw_slice(len);
|
||||
|
||||
// SAFETY: After allocating raw storage for exactly `len` values, we
|
||||
// must fully initialize the storage without panicking, and we must
|
||||
// also prevent the stale values in the vec from being dropped.
|
||||
Ok(unsafe {
|
||||
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)
|
||||
})
|
||||
|
|
@ -432,7 +451,7 @@ impl DroplessArena {
|
|||
let bytes = align_up(layout.size(), DROPLESS_ALIGNMENT);
|
||||
|
||||
// Tell LLVM that `end` is aligned to DROPLESS_ALIGNMENT.
|
||||
unsafe { intrinsics::assume(end == align_down(end, DROPLESS_ALIGNMENT)) };
|
||||
unsafe { hint::assert_unchecked(end == align_down(end, DROPLESS_ALIGNMENT)) };
|
||||
|
||||
if let Some(sub) = end.checked_sub(bytes) {
|
||||
let new_end = align_down(sub, layout.align());
|
||||
|
|
@ -490,19 +509,6 @@ 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.
|
||||
///
|
||||
|
|
@ -584,7 +590,7 @@ impl DroplessArena {
|
|||
&self,
|
||||
iter: impl IntoIterator<Item = Result<T, E>>,
|
||||
) -> Result<&mut [T], E> {
|
||||
// Despite the similarlty with `alloc_from_iter`, we cannot reuse their fast case, as we
|
||||
// Despite the similarity 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,11 +656,7 @@ 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 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()?);
|
||||
}
|
||||
let tys = pats.iter().map(|pat| pat.to_ty()).collect::<Option<ThinVec<_>>>()?;
|
||||
TyKind::Tup(tys)
|
||||
}
|
||||
_ => return None,
|
||||
|
|
@ -3873,27 +3869,44 @@ pub struct ConstItem {
|
|||
pub ident: Ident,
|
||||
pub generics: Generics,
|
||||
pub ty: Box<Ty>,
|
||||
pub rhs: Option<ConstItemRhs>,
|
||||
pub rhs_kind: ConstItemRhsKind,
|
||||
pub define_opaque: Option<ThinVec<(NodeId, Path)>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
||||
pub enum ConstItemRhs {
|
||||
TypeConst(AnonConst),
|
||||
Body(Box<Expr>),
|
||||
pub enum ConstItemRhsKind {
|
||||
Body { rhs: Option<Box<Expr>> },
|
||||
TypeConst { rhs: Option<AnonConst> },
|
||||
}
|
||||
|
||||
impl ConstItemRhs {
|
||||
pub fn span(&self) -> Span {
|
||||
self.expr().span
|
||||
impl ConstItemRhsKind {
|
||||
pub fn new_body(rhs: Box<Expr>) -> Self {
|
||||
Self::Body { rhs: Some(rhs) }
|
||||
}
|
||||
|
||||
pub fn expr(&self) -> &Expr {
|
||||
pub fn span(&self) -> Option<Span> {
|
||||
Some(self.expr()?.span)
|
||||
}
|
||||
|
||||
pub fn expr(&self) -> Option<&Expr> {
|
||||
match self {
|
||||
ConstItemRhs::TypeConst(anon_const) => &anon_const.value,
|
||||
ConstItemRhs::Body(expr) => expr,
|
||||
Self::Body { rhs: Some(body) } => Some(&body),
|
||||
Self::TypeConst { rhs: Some(anon) } => Some(&anon.value),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_expr(&self) -> bool {
|
||||
match self {
|
||||
Self::Body { rhs: Some(_) } => true,
|
||||
Self::TypeConst { rhs: Some(_) } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_type_const(&self) -> bool {
|
||||
matches!(self, &Self::TypeConst { .. })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
||||
|
|
|
|||
|
|
@ -354,7 +354,13 @@ fn make_attr_token_stream(
|
|||
FrameData { open_delim_sp: Some((delim, span, spacing)), inner: vec![] },
|
||||
));
|
||||
} else if let Some(delim) = kind.close_delim() {
|
||||
let frame_data = mem::replace(&mut stack_top, stack_rest.pop().unwrap());
|
||||
// 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 (open_delim, open_sp, open_spacing) = frame_data.open_delim_sp.unwrap();
|
||||
assert!(
|
||||
open_delim.eq_ignoring_invisible_origin(&delim),
|
||||
|
|
|
|||
|
|
@ -427,7 +427,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
Const,
|
||||
ConstBlockItem,
|
||||
ConstItem,
|
||||
ConstItemRhs,
|
||||
ConstItemRhsKind,
|
||||
Defaultness,
|
||||
Delegation,
|
||||
DelegationMac,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ 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" }
|
||||
|
|
|
|||
|
|
@ -1,191 +0,0 @@
|
|||
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,6 +3,7 @@ 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;
|
||||
|
|
@ -19,8 +20,7 @@ use super::errors::{
|
|||
RegisterConflict,
|
||||
};
|
||||
use crate::{
|
||||
AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, ParamMode,
|
||||
ResolverAstLoweringExt, fluent_generated as fluent,
|
||||
AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, ParamMode, ResolverAstLoweringExt,
|
||||
};
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
|
|
@ -67,7 +67,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
&self.tcx.sess,
|
||||
sym::asm_experimental_arch,
|
||||
sp,
|
||||
fluent::ast_lowering_unstable_inline_assembly,
|
||||
msg!("inline assembly is not stable yet on this architecture"),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
|
@ -84,7 +84,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
&self.tcx.sess,
|
||||
sym::asm_unwind,
|
||||
sp,
|
||||
fluent::ast_lowering_unstable_may_unwind,
|
||||
msg!("the `may_unwind` option is unstable"),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
|
@ -499,7 +499,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
sess,
|
||||
sym::asm_goto_with_outputs,
|
||||
*op_sp,
|
||||
fluent::ast_lowering_unstable_inline_assembly_label_operand_with_outputs,
|
||||
msg!("using both label and output operands for inline assembly is unstable"),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,17 +4,17 @@ use rustc_macros::{Diagnostic, Subdiagnostic};
|
|||
use rustc_span::{Ident, Span, Symbol};
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_generic_type_with_parentheses, code = E0214)]
|
||||
#[diag("parenthesized type parameters may only be used with a `Fn` trait", code = E0214)]
|
||||
pub(crate) struct GenericTypeWithParentheses {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
#[label("only `Fn` traits may use parentheses")]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub sub: Option<UseAngleBrackets>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(ast_lowering_use_angle_brackets, applicability = "maybe-incorrect")]
|
||||
#[multipart_suggestion("use angle brackets instead", 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(ast_lowering_invalid_abi, code = E0703)]
|
||||
#[note]
|
||||
#[diag("invalid ABI: found `{$abi}`", code = E0703)]
|
||||
#[note("invoke `{$command}` for a full list of supported calling conventions")]
|
||||
pub(crate) struct InvalidAbi {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
#[label("invalid ABI")]
|
||||
pub span: Span,
|
||||
pub abi: Symbol,
|
||||
pub command: String,
|
||||
|
|
@ -36,16 +36,16 @@ pub(crate) struct InvalidAbi {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_default_field_in_tuple)]
|
||||
#[diag("default fields are not supported in tuple structs")]
|
||||
pub(crate) struct TupleStructWithDefault {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
#[label("default fields are only supported on structs")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(
|
||||
ast_lowering_invalid_abi_suggestion,
|
||||
"there's a similarly named valid ABI `{$suggestion}`",
|
||||
code = "\"{suggestion}\"",
|
||||
applicability = "maybe-incorrect",
|
||||
style = "verbose"
|
||||
|
|
@ -57,7 +57,7 @@ pub(crate) struct InvalidAbiSuggestion {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_assoc_ty_parentheses)]
|
||||
#[diag("parenthesized generic arguments cannot be used in associated type constraints")]
|
||||
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(ast_lowering_remove_parentheses)]
|
||||
#[multipart_suggestion("remove these parentheses")]
|
||||
Empty {
|
||||
#[suggestion_part(code = "")]
|
||||
parentheses_span: Span,
|
||||
},
|
||||
#[multipart_suggestion(ast_lowering_use_angle_brackets)]
|
||||
#[multipart_suggestion("use angle brackets instead")]
|
||||
NotEmpty {
|
||||
#[suggestion_part(code = "<")]
|
||||
open_param: Span,
|
||||
|
|
@ -82,8 +82,8 @@ pub(crate) enum AssocTyParenthesesSub {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_misplaced_impl_trait, code = E0562)]
|
||||
#[note]
|
||||
#[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")]
|
||||
pub(crate) struct MisplacedImplTrait<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -91,97 +91,106 @@ pub(crate) struct MisplacedImplTrait<'a> {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_assoc_ty_binding_in_dyn)]
|
||||
#[diag("associated type bounds are not allowed in `dyn` types")]
|
||||
pub(crate) struct MisplacedAssocTyBinding {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(code = " = impl", applicability = "maybe-incorrect", style = "verbose")]
|
||||
#[suggestion(
|
||||
"use `impl Trait` to introduce a type instead",
|
||||
code = " = impl",
|
||||
applicability = "maybe-incorrect",
|
||||
style = "verbose"
|
||||
)]
|
||||
pub suggestion: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_underscore_expr_lhs_assign)]
|
||||
#[diag("in expressions, `_` can only be used on the left-hand side of an assignment")]
|
||||
pub(crate) struct UnderscoreExprLhsAssign {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
#[label("`_` not allowed here")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_await_only_in_async_fn_and_blocks, code = E0728)]
|
||||
#[diag("`await` is only allowed inside `async` functions and blocks", code = E0728)]
|
||||
pub(crate) struct AwaitOnlyInAsyncFnAndBlocks {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
#[label("only allowed inside `async` functions and blocks")]
|
||||
pub await_kw_span: Span,
|
||||
#[label(ast_lowering_this_not_async)]
|
||||
#[label("this is not `async`")]
|
||||
pub item_span: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_coroutine_too_many_parameters, code = E0628)]
|
||||
#[diag("too many parameters for a coroutine (expected 0 or 1 parameters)", code = E0628)]
|
||||
pub(crate) struct CoroutineTooManyParameters {
|
||||
#[primary_span]
|
||||
pub fn_decl_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_closure_cannot_be_static, code = E0697)]
|
||||
#[diag("closures cannot be static", code = E0697)]
|
||||
pub(crate) struct ClosureCannotBeStatic {
|
||||
#[primary_span]
|
||||
pub fn_decl_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_functional_record_update_destructuring_assignment)]
|
||||
#[diag("functional record updates are not allowed in destructuring assignments")]
|
||||
pub(crate) struct FunctionalRecordUpdateDestructuringAssignment {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||
#[suggestion(
|
||||
"consider removing the trailing pattern",
|
||||
code = "",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_async_coroutines_not_supported, code = E0727)]
|
||||
#[diag("`async` coroutines are not yet supported", code = E0727)]
|
||||
pub(crate) struct AsyncCoroutinesNotSupported {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_inline_asm_unsupported_target, code = E0472)]
|
||||
#[diag("inline assembly is unsupported on this target", code = E0472)]
|
||||
pub(crate) struct InlineAsmUnsupportedTarget {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_att_syntax_only_x86)]
|
||||
#[diag("the `att_syntax` option is only supported on x86")]
|
||||
pub(crate) struct AttSyntaxOnlyX86 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_abi_specified_multiple_times)]
|
||||
#[diag("`{$prev_name}` ABI specified multiple times")]
|
||||
pub(crate) struct AbiSpecifiedMultipleTimes {
|
||||
#[primary_span]
|
||||
pub abi_span: Span,
|
||||
pub prev_name: Symbol,
|
||||
#[label]
|
||||
#[label("previously specified here")]
|
||||
pub prev_span: Span,
|
||||
#[note]
|
||||
#[note("these ABIs are equivalent on the current target")]
|
||||
pub equivalent: bool,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_clobber_abi_not_supported)]
|
||||
#[diag("`clobber_abi` is not supported on this target")]
|
||||
pub(crate) struct ClobberAbiNotSupported {
|
||||
#[primary_span]
|
||||
pub abi_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[note]
|
||||
#[diag(ast_lowering_invalid_abi_clobber_abi)]
|
||||
#[note("the following ABIs are supported on this target: {$supported_abis}")]
|
||||
#[diag("invalid ABI for `clobber_abi`")]
|
||||
pub(crate) struct InvalidAbiClobberAbi {
|
||||
#[primary_span]
|
||||
pub abi_span: Span,
|
||||
|
|
@ -189,7 +198,7 @@ pub(crate) struct InvalidAbiClobberAbi {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_invalid_register)]
|
||||
#[diag("invalid register `{$reg}`: {$error}")]
|
||||
pub(crate) struct InvalidRegister<'a> {
|
||||
#[primary_span]
|
||||
pub op_span: Span,
|
||||
|
|
@ -198,8 +207,10 @@ pub(crate) struct InvalidRegister<'a> {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[note]
|
||||
#[diag(ast_lowering_invalid_register_class)]
|
||||
#[note(
|
||||
"the following register classes are supported on this target: {$supported_register_classes}"
|
||||
)]
|
||||
#[diag("invalid register class `{$reg_class}`: unknown register class")]
|
||||
pub(crate) struct InvalidRegisterClass {
|
||||
#[primary_span]
|
||||
pub op_span: Span,
|
||||
|
|
@ -208,12 +219,12 @@ pub(crate) struct InvalidRegisterClass {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_invalid_asm_template_modifier_reg_class)]
|
||||
#[diag("invalid asm template modifier for this register class")]
|
||||
pub(crate) struct InvalidAsmTemplateModifierRegClass {
|
||||
#[primary_span]
|
||||
#[label(ast_lowering_template_modifier)]
|
||||
#[label("template modifier")]
|
||||
pub placeholder_span: Span,
|
||||
#[label(ast_lowering_argument)]
|
||||
#[label("argument")]
|
||||
pub op_span: Span,
|
||||
#[subdiagnostic]
|
||||
pub sub: InvalidAsmTemplateModifierRegClassSub,
|
||||
|
|
@ -221,44 +232,48 @@ pub(crate) struct InvalidAsmTemplateModifierRegClass {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum InvalidAsmTemplateModifierRegClassSub {
|
||||
#[note(ast_lowering_support_modifiers)]
|
||||
#[note(
|
||||
"the `{$class_name}` register class supports the following template modifiers: {$modifiers}"
|
||||
)]
|
||||
SupportModifier { class_name: Symbol, modifiers: String },
|
||||
#[note(ast_lowering_does_not_support_modifiers)]
|
||||
#[note("the `{$class_name}` register class does not support template modifiers")]
|
||||
DoesNotSupportModifier { class_name: Symbol },
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_invalid_asm_template_modifier_const)]
|
||||
#[diag("asm template modifiers are not allowed for `const` arguments")]
|
||||
pub(crate) struct InvalidAsmTemplateModifierConst {
|
||||
#[primary_span]
|
||||
#[label(ast_lowering_template_modifier)]
|
||||
#[label("template modifier")]
|
||||
pub placeholder_span: Span,
|
||||
#[label(ast_lowering_argument)]
|
||||
#[label("argument")]
|
||||
pub op_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_invalid_asm_template_modifier_sym)]
|
||||
#[diag("asm template modifiers are not allowed for `sym` arguments")]
|
||||
pub(crate) struct InvalidAsmTemplateModifierSym {
|
||||
#[primary_span]
|
||||
#[label(ast_lowering_template_modifier)]
|
||||
#[label("template modifier")]
|
||||
pub placeholder_span: Span,
|
||||
#[label(ast_lowering_argument)]
|
||||
#[label("argument")]
|
||||
pub op_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_invalid_asm_template_modifier_label)]
|
||||
#[diag("asm template modifiers are not allowed for `label` arguments")]
|
||||
pub(crate) struct InvalidAsmTemplateModifierLabel {
|
||||
#[primary_span]
|
||||
#[label(ast_lowering_template_modifier)]
|
||||
#[label("template modifier")]
|
||||
pub placeholder_span: Span,
|
||||
#[label(ast_lowering_argument)]
|
||||
#[label("argument")]
|
||||
pub op_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_register_class_only_clobber)]
|
||||
#[diag(
|
||||
"register class `{$reg_class_name}` can only be used as a clobber, not as an input or output"
|
||||
)]
|
||||
pub(crate) struct RegisterClassOnlyClobber {
|
||||
#[primary_span]
|
||||
pub op_span: Span,
|
||||
|
|
@ -266,7 +281,7 @@ pub(crate) struct RegisterClassOnlyClobber {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_register_class_only_clobber_stable)]
|
||||
#[diag("register class `{$reg_class_name}` can only be used as a clobber in stable")]
|
||||
pub(crate) struct RegisterClassOnlyClobberStable {
|
||||
#[primary_span]
|
||||
pub op_span: Span,
|
||||
|
|
@ -274,27 +289,27 @@ pub(crate) struct RegisterClassOnlyClobberStable {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_register_conflict)]
|
||||
#[diag("register `{$reg1_name}` conflicts with register `{$reg2_name}`")]
|
||||
pub(crate) struct RegisterConflict<'a> {
|
||||
#[primary_span]
|
||||
#[label(ast_lowering_register1)]
|
||||
#[label("register `{$reg1_name}`")]
|
||||
pub op_span1: Span,
|
||||
#[label(ast_lowering_register2)]
|
||||
#[label("register `{$reg2_name}`")]
|
||||
pub op_span2: Span,
|
||||
pub reg1_name: &'a str,
|
||||
pub reg2_name: &'a str,
|
||||
#[help]
|
||||
#[help("use `lateout` instead of `out` to avoid conflict")]
|
||||
pub in_out: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[help]
|
||||
#[diag(ast_lowering_sub_tuple_binding)]
|
||||
#[help("remove this and bind each tuple field independently")]
|
||||
#[diag("`{$ident_name} @` is not allowed in a {$ctx}")]
|
||||
pub(crate) struct SubTupleBinding<'a> {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
#[label("this is only allowed in slice patterns")]
|
||||
#[suggestion(
|
||||
ast_lowering_sub_tuple_binding_suggestion,
|
||||
"if you don't need to use the contents of {$ident}, discard the tuple's remaining fields",
|
||||
style = "verbose",
|
||||
code = "..",
|
||||
applicability = "maybe-incorrect"
|
||||
|
|
@ -306,63 +321,67 @@ pub(crate) struct SubTupleBinding<'a> {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_extra_double_dot)]
|
||||
#[diag("`..` can only be used once per {$ctx} pattern")]
|
||||
pub(crate) struct ExtraDoubleDot<'a> {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
#[label("can only be used once per {$ctx} pattern")]
|
||||
pub span: Span,
|
||||
#[label(ast_lowering_previously_used_here)]
|
||||
#[label("previously used here")]
|
||||
pub prev_span: Span,
|
||||
pub ctx: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[note]
|
||||
#[diag(ast_lowering_misplaced_double_dot)]
|
||||
#[note("only allowed in tuple, tuple struct, and slice patterns")]
|
||||
#[diag("`..` patterns are not allowed here")]
|
||||
pub(crate) struct MisplacedDoubleDot {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_match_arm_with_no_body)]
|
||||
#[diag("`match` arm with no body")]
|
||||
pub(crate) struct MatchArmWithNoBody {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(code = " => todo!(),", applicability = "has-placeholders")]
|
||||
#[suggestion(
|
||||
"add a body after the pattern",
|
||||
code = " => todo!(),",
|
||||
applicability = "has-placeholders"
|
||||
)]
|
||||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_never_pattern_with_body)]
|
||||
#[diag("a never pattern is always unreachable")]
|
||||
pub(crate) struct NeverPatternWithBody {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
#[suggestion(code = "", applicability = "maybe-incorrect")]
|
||||
#[label("this will never be executed")]
|
||||
#[suggestion("remove this expression", code = "", applicability = "maybe-incorrect")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_never_pattern_with_guard)]
|
||||
#[diag("a guard on a never pattern will never be run")]
|
||||
pub(crate) struct NeverPatternWithGuard {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "", applicability = "maybe-incorrect")]
|
||||
#[suggestion("remove this guard", code = "", applicability = "maybe-incorrect")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_arbitrary_expression_in_pattern)]
|
||||
#[diag("arbitrary expressions aren't allowed in patterns")]
|
||||
pub(crate) struct ArbitraryExpressionInPattern {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[note(ast_lowering_pattern_from_macro_note)]
|
||||
#[note("the `expr` fragment specifier forces the metavariable's content to be an expression")]
|
||||
pub pattern_from_macro_note: bool,
|
||||
#[help(ast_lowering_const_block_in_pattern_help)]
|
||||
#[help("use a named `const`-item or an `if`-guard (`x if x == const {\"{ ... }\"}`) instead")]
|
||||
pub const_block_in_pattern_help: bool,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_inclusive_range_with_no_end)]
|
||||
#[diag("inclusive range with no end")]
|
||||
pub(crate) struct InclusiveRangeWithNoEnd {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -370,7 +389,7 @@ pub(crate) struct InclusiveRangeWithNoEnd {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
ast_lowering_bad_return_type_notation_output_suggestion,
|
||||
"use the right argument notation and remove the return type",
|
||||
applicability = "machine-applicable",
|
||||
style = "verbose"
|
||||
)]
|
||||
|
|
@ -384,26 +403,36 @@ pub(crate) struct RTNSuggestion {
|
|||
|
||||
#[derive(Diagnostic)]
|
||||
pub(crate) enum BadReturnTypeNotation {
|
||||
#[diag(ast_lowering_bad_return_type_notation_inputs)]
|
||||
#[diag("argument types not allowed with return type notation")]
|
||||
Inputs {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "(..)", applicability = "machine-applicable", style = "verbose")]
|
||||
#[suggestion(
|
||||
"remove the input types",
|
||||
code = "(..)",
|
||||
applicability = "machine-applicable",
|
||||
style = "verbose"
|
||||
)]
|
||||
span: Span,
|
||||
},
|
||||
#[diag(ast_lowering_bad_return_type_notation_output)]
|
||||
#[diag("return type not allowed with return type notation")]
|
||||
Output {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[subdiagnostic]
|
||||
suggestion: RTNSuggestion,
|
||||
},
|
||||
#[diag(ast_lowering_bad_return_type_notation_needs_dots)]
|
||||
#[diag("return type notation arguments must be elided with `..`")]
|
||||
NeedsDots {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "(..)", applicability = "machine-applicable", style = "verbose")]
|
||||
#[suggestion(
|
||||
"use the correct syntax by adding `..` to the arguments",
|
||||
code = "(..)",
|
||||
applicability = "machine-applicable",
|
||||
style = "verbose"
|
||||
)]
|
||||
span: Span,
|
||||
},
|
||||
#[diag(ast_lowering_bad_return_type_notation_position)]
|
||||
#[diag("return type notation not allowed in this position yet")]
|
||||
Position {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
|
|
@ -411,14 +440,14 @@ pub(crate) enum BadReturnTypeNotation {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_generic_param_default_in_binder)]
|
||||
#[diag("defaults for generic parameters are not allowed in `for<...>` binders")]
|
||||
pub(crate) struct GenericParamDefaultInBinder {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_async_bound_not_on_trait)]
|
||||
#[diag("`async` bound modifier only allowed on trait, not `{$descr}`")]
|
||||
pub(crate) struct AsyncBoundNotOnTrait {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -426,30 +455,37 @@ pub(crate) struct AsyncBoundNotOnTrait {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_async_bound_only_for_fn_traits)]
|
||||
#[diag("`async` bound modifier only allowed on `Fn`/`FnMut`/`FnOnce` traits")]
|
||||
pub(crate) struct AsyncBoundOnlyForFnTraits {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_no_precise_captures_on_apit)]
|
||||
#[diag("`use<...>` precise capturing syntax not allowed in argument-position `impl Trait`")]
|
||||
pub(crate) struct NoPreciseCapturesOnApit {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_yield_in_closure)]
|
||||
#[diag("`yield` can only be used in `#[coroutine]` closures, or `gen` blocks")]
|
||||
pub(crate) struct YieldInClosure {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(code = "#[coroutine] ", applicability = "maybe-incorrect", style = "verbose")]
|
||||
#[suggestion(
|
||||
"use `#[coroutine]` to make this closure a coroutine",
|
||||
code = "#[coroutine] ",
|
||||
applicability = "maybe-incorrect",
|
||||
style = "verbose"
|
||||
)]
|
||||
pub suggestion: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_invalid_legacy_const_generic_arg)]
|
||||
#[diag(
|
||||
"invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items"
|
||||
)]
|
||||
pub(crate) struct InvalidLegacyConstGenericArg {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -459,7 +495,7 @@ pub(crate) struct InvalidLegacyConstGenericArg {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
ast_lowering_invalid_legacy_const_generic_arg_suggestion,
|
||||
"try using a const generic argument instead",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
pub(crate) struct UseConstGenericArg {
|
||||
|
|
@ -472,21 +508,21 @@ pub(crate) struct UseConstGenericArg {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_union_default_field_values)]
|
||||
#[diag("unions cannot have default field values")]
|
||||
pub(crate) struct UnionWithDefault {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_delegation_unresolved_callee)]
|
||||
#[diag("failed to resolve delegation callee")]
|
||||
pub(crate) struct UnresolvedDelegationCallee {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_delegation_cycle_in_signature_resolution)]
|
||||
#[diag("encountered a cycle during delegation signature resolution")]
|
||||
pub(crate) struct CycleInDelegationSignatureResolution {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ 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};
|
||||
|
|
@ -28,9 +29,7 @@ use super::{
|
|||
GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt,
|
||||
};
|
||||
use crate::errors::{InvalidLegacyConstGenericArg, UseConstGenericArg, YieldInClosure};
|
||||
use crate::{
|
||||
AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition, TryBlockScope, fluent_generated,
|
||||
};
|
||||
use crate::{AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition, TryBlockScope};
|
||||
|
||||
struct WillCreateDefIdsVisitor {}
|
||||
|
||||
|
|
@ -967,14 +966,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)
|
||||
self.arm(ready_pat, break_x, span)
|
||||
};
|
||||
|
||||
// `::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)
|
||||
self.arm(pending_pat, empty_block, span)
|
||||
};
|
||||
|
||||
let inner_match_stmt = {
|
||||
|
|
@ -1028,7 +1027,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
});
|
||||
|
||||
// mut __awaitee => loop { ... }
|
||||
let awaitee_arm = self.arm(awaitee_pat, loop_expr);
|
||||
let awaitee_arm = self.arm(awaitee_pat, loop_expr, span);
|
||||
|
||||
// `match ::std::future::IntoFuture::into_future(<expr>) { ... }`
|
||||
let into_future_expr = match await_kind {
|
||||
|
|
@ -1703,7 +1702,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
&self.tcx.sess,
|
||||
sym::yield_expr,
|
||||
span,
|
||||
fluent_generated::ast_lowering_yield,
|
||||
msg!("yield syntax is experimental"),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
|
@ -1818,7 +1817,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)
|
||||
self.arm(pat, break_expr, for_span)
|
||||
};
|
||||
|
||||
// Some(<pat>) => <body>,
|
||||
|
|
@ -1827,7 +1826,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)
|
||||
self.arm(some_pat, body_expr, for_span)
|
||||
};
|
||||
|
||||
// `mut iter`
|
||||
|
|
@ -1886,7 +1885,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);
|
||||
let iter_arm = self.arm(iter_pat, loop_expr, for_span);
|
||||
|
||||
let match_expr = match loop_kind {
|
||||
ForLoopKind::For => {
|
||||
|
|
@ -1931,7 +1930,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
hir::LangItem::IntoAsyncIterIntoIter,
|
||||
arena_vec![self; head],
|
||||
);
|
||||
let iter_arm = self.arm(async_iter_pat, inner_match_expr);
|
||||
let iter_arm = self.arm(async_iter_pat, inner_match_expr, for_span);
|
||||
self.arena.alloc(self.expr_match(
|
||||
for_span,
|
||||
iter,
|
||||
|
|
@ -1998,7 +1997,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)
|
||||
self.arm(continue_pat, val_expr, try_span)
|
||||
};
|
||||
|
||||
// `ControlFlow::Break(residual) =>
|
||||
|
|
@ -2041,7 +2040,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)
|
||||
self.arm(break_pat, ret_expr, try_span)
|
||||
};
|
||||
|
||||
hir::ExprKind::Match(
|
||||
|
|
@ -2369,12 +2368,13 @@ 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(expr.span),
|
||||
span: self.lower_span(span),
|
||||
body: expr,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -288,7 +288,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ident,
|
||||
generics,
|
||||
ty,
|
||||
rhs,
|
||||
rhs_kind,
|
||||
define_opaque,
|
||||
}) => {
|
||||
let ident = self.lower_ident(*ident);
|
||||
|
|
@ -301,7 +301,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ty,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
|
||||
);
|
||||
let rhs = this.lower_const_item_rhs(attrs, rhs.as_ref(), span);
|
||||
let rhs = this.lower_const_item_rhs(rhs_kind, span);
|
||||
(ty, rhs)
|
||||
},
|
||||
);
|
||||
|
|
@ -827,7 +827,10 @@ 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)),
|
||||
disr_expr: v
|
||||
.disr_expr
|
||||
.as_ref()
|
||||
.map(|e| self.lower_anon_const_to_anon_const(e, e.value.span)),
|
||||
ident: self.lower_ident(v.ident),
|
||||
span: self.lower_span(v.span),
|
||||
}
|
||||
|
|
@ -917,7 +920,10 @@ 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)),
|
||||
default: f
|
||||
.default
|
||||
.as_ref()
|
||||
.map(|v| self.lower_anon_const_to_anon_const(v, v.value.span)),
|
||||
ty,
|
||||
safety: self.lower_safety(f.safety, hir::Safety::Safe),
|
||||
}
|
||||
|
|
@ -935,7 +941,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
let (ident, generics, kind, has_default) = match &i.kind {
|
||||
AssocItemKind::Const(box ConstItem {
|
||||
ident, generics, ty, rhs, define_opaque, ..
|
||||
ident,
|
||||
generics,
|
||||
ty,
|
||||
rhs_kind,
|
||||
define_opaque,
|
||||
..
|
||||
}) => {
|
||||
let (generics, kind) = self.lower_generics(
|
||||
generics,
|
||||
|
|
@ -946,15 +957,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ty,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
|
||||
);
|
||||
let rhs = rhs
|
||||
.as_ref()
|
||||
.map(|rhs| this.lower_const_item_rhs(attrs, Some(rhs), i.span));
|
||||
hir::TraitItemKind::Const(ty, rhs)
|
||||
// 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())
|
||||
},
|
||||
);
|
||||
|
||||
if define_opaque.is_some() {
|
||||
if rhs.is_some() {
|
||||
if rhs_kind.has_expr() {
|
||||
self.lower_define_opaque(hir_id, &define_opaque);
|
||||
} else {
|
||||
self.dcx().span_err(
|
||||
|
|
@ -964,7 +978,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
(*ident, generics, kind, rhs.is_some())
|
||||
(*ident, generics, kind, rhs_kind.has_expr())
|
||||
}
|
||||
AssocItemKind::Fn(box Fn {
|
||||
sig, ident, generics, body: None, define_opaque, ..
|
||||
|
|
@ -1148,7 +1162,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
let (ident, (generics, kind)) = match &i.kind {
|
||||
AssocItemKind::Const(box ConstItem {
|
||||
ident, generics, ty, rhs, define_opaque, ..
|
||||
ident,
|
||||
generics,
|
||||
ty,
|
||||
rhs_kind,
|
||||
define_opaque,
|
||||
..
|
||||
}) => (
|
||||
*ident,
|
||||
self.lower_generics(
|
||||
|
|
@ -1161,7 +1180,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
|
||||
);
|
||||
this.lower_define_opaque(hir_id, &define_opaque);
|
||||
let rhs = this.lower_const_item_rhs(attrs, rhs.as_ref(), i.span);
|
||||
let rhs = this.lower_const_item_rhs(rhs_kind, i.span);
|
||||
hir::ImplItemKind::Const(ty, rhs)
|
||||
},
|
||||
),
|
||||
|
|
@ -1391,7 +1410,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 attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic))
|
||||
if find_attr!(attrs, AttributeKind::RustcIntrinsic)
|
||||
|| this.tcx.is_sdylib_interface_build()
|
||||
{
|
||||
let span = this.lower_span(span);
|
||||
|
|
|
|||
|
|
@ -88,8 +88,6 @@ 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,
|
||||
|
|
@ -880,7 +878,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
|
||||
|
|
@ -1933,26 +1931,29 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
source: LifetimeSource,
|
||||
syntax: LifetimeSyntax,
|
||||
) -> &'hir hir::Lifetime {
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hir::LifetimeKind::Error(self.dcx().span_delayed_bug(ident.span, "unresolved lifetime"))
|
||||
};
|
||||
|
||||
debug!(?res);
|
||||
|
|
@ -2016,12 +2017,13 @@ 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 };
|
||||
|
||||
|
|
@ -2376,15 +2378,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
fn lower_const_item_rhs(
|
||||
&mut self,
|
||||
attrs: &[hir::Attribute],
|
||||
rhs: Option<&ConstItemRhs>,
|
||||
rhs_kind: &ConstItemRhsKind,
|
||||
span: Span,
|
||||
) -> hir::ConstItemRhs<'hir> {
|
||||
match rhs {
|
||||
Some(ConstItemRhs::TypeConst(anon)) => {
|
||||
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) } => {
|
||||
hir::ConstItemRhs::TypeConst(self.lower_anon_const_to_const_arg_and_alloc(anon))
|
||||
}
|
||||
None if find_attr!(attrs, AttributeKind::TypeConst(_)) => {
|
||||
ConstItemRhsKind::TypeConst { rhs: None } => {
|
||||
let const_arg = ConstArg {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ConstArgKind::Error(
|
||||
|
|
@ -2394,10 +2401,6 @@ 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)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2427,15 +2430,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
);
|
||||
|
||||
let lowered_args = self.arena.alloc_from_iter(args.iter().map(|arg| {
|
||||
let const_arg = if let ExprKind::ConstBlock(anon_const) = &arg.kind {
|
||||
let def_id = self.local_def_id(anon_const.id);
|
||||
let def_kind = self.tcx.def_kind(def_id);
|
||||
assert_eq!(DefKind::AnonConst, def_kind);
|
||||
self.lower_anon_const_to_const_arg(anon_const)
|
||||
} else {
|
||||
self.lower_expr_to_const_arg_direct(arg)
|
||||
};
|
||||
|
||||
let const_arg = self.lower_expr_to_const_arg_direct(arg);
|
||||
&*self.arena.alloc(const_arg)
|
||||
}));
|
||||
|
||||
|
|
@ -2447,16 +2442,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
ExprKind::Tup(exprs) => {
|
||||
let exprs = self.arena.alloc_from_iter(exprs.iter().map(|expr| {
|
||||
let expr = if let ExprKind::ConstBlock(anon_const) = &expr.kind {
|
||||
let def_id = self.local_def_id(anon_const.id);
|
||||
let def_kind = self.tcx.def_kind(def_id);
|
||||
assert_eq!(DefKind::AnonConst, def_kind);
|
||||
|
||||
self.lower_anon_const_to_const_arg(anon_const)
|
||||
} else {
|
||||
self.lower_expr_to_const_arg_direct(&expr)
|
||||
};
|
||||
|
||||
let expr = self.lower_expr_to_const_arg_direct(&expr);
|
||||
&*self.arena.alloc(expr)
|
||||
}));
|
||||
|
||||
|
|
@ -2496,16 +2482,7 @@ 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 = 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)
|
||||
};
|
||||
let expr = self.lower_expr_to_const_arg_direct(&f.expr);
|
||||
|
||||
&*self.arena.alloc(hir::ConstArgExprField {
|
||||
hir_id,
|
||||
|
|
@ -2523,13 +2500,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
ExprKind::Array(elements) => {
|
||||
let lowered_elems = self.arena.alloc_from_iter(elements.iter().map(|element| {
|
||||
let const_arg = if let ExprKind::ConstBlock(anon_const) = &element.kind {
|
||||
let def_id = self.local_def_id(anon_const.id);
|
||||
assert_eq!(DefKind::AnonConst, self.tcx.def_kind(def_id));
|
||||
self.lower_anon_const_to_const_arg(anon_const)
|
||||
} else {
|
||||
self.lower_expr_to_const_arg_direct(element)
|
||||
};
|
||||
let const_arg = self.lower_expr_to_const_arg_direct(element);
|
||||
&*self.arena.alloc(const_arg)
|
||||
}));
|
||||
let array_expr = self.arena.alloc(hir::ConstArgArrayExpr {
|
||||
|
|
@ -2559,6 +2530,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
| ExprKind::Call(..)
|
||||
| ExprKind::Tup(..)
|
||||
| ExprKind::Array(..)
|
||||
| ExprKind::ConstBlock(..)
|
||||
)
|
||||
{
|
||||
return self.lower_expr_to_const_arg_direct(expr);
|
||||
|
|
@ -2572,10 +2544,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
ConstArg {
|
||||
hir_id: self.lower_node_id(expr.id),
|
||||
kind: hir::ConstArgKind::Literal(literal.node),
|
||||
kind: hir::ConstArgKind::Literal { lit: literal.node, negated: false },
|
||||
span,
|
||||
}
|
||||
}
|
||||
ExprKind::Unary(UnOp::Neg, inner_expr)
|
||||
if let ExprKind::Lit(literal) = &inner_expr.kind =>
|
||||
{
|
||||
let span = expr.span;
|
||||
let literal = self.lower_lit(literal, span);
|
||||
|
||||
ConstArg {
|
||||
hir_id: self.lower_node_id(expr.id),
|
||||
kind: hir::ConstArgKind::Literal { lit: literal.node, negated: true },
|
||||
span,
|
||||
}
|
||||
}
|
||||
ExprKind::ConstBlock(anon_const) => {
|
||||
let def_id = self.local_def_id(anon_const.id);
|
||||
assert_eq!(DefKind::AnonConst, self.tcx.def_kind(def_id));
|
||||
self.lower_anon_const_to_const_arg(anon_const, span)
|
||||
}
|
||||
_ => overly_complex_const(self),
|
||||
}
|
||||
}
|
||||
|
|
@ -2586,11 +2575,15 @@ 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))
|
||||
self.arena.alloc(self.lower_anon_const_to_const_arg(anon, anon.value.span))
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> {
|
||||
fn lower_anon_const_to_const_arg(
|
||||
&mut self,
|
||||
anon: &AnonConst,
|
||||
span: Span,
|
||||
) -> hir::ConstArg<'hir> {
|
||||
let tcx = self.tcx;
|
||||
|
||||
// We cannot change parsing depending on feature gates available,
|
||||
|
|
@ -2601,7 +2594,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);
|
||||
let lowered_anon = self.lower_anon_const_to_anon_const(anon, span);
|
||||
ConstArg {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ConstArgKind::Anon(lowered_anon),
|
||||
|
|
@ -2647,7 +2640,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
};
|
||||
}
|
||||
|
||||
let lowered_anon = self.lower_anon_const_to_anon_const(anon);
|
||||
let lowered_anon = self.lower_anon_const_to_anon_const(anon, anon.value.span);
|
||||
ConstArg {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ConstArgKind::Anon(lowered_anon),
|
||||
|
|
@ -2657,7 +2650,11 @@ 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) -> &'hir hir::AnonConst {
|
||||
fn lower_anon_const_to_anon_const(
|
||||
&mut self,
|
||||
c: &AnonConst,
|
||||
span: Span,
|
||||
) -> &'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);
|
||||
|
|
@ -2665,7 +2662,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(c.value.span),
|
||||
span: this.lower_span(span),
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ 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" }
|
||||
|
|
|
|||
|
|
@ -1,342 +0,0 @@
|
|||
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
|
||||
|
|
@ -1361,9 +1361,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
});
|
||||
}
|
||||
ItemKind::Const(box ConstItem { defaultness, ident, rhs, .. }) => {
|
||||
ItemKind::Const(box ConstItem { defaultness, ident, rhs_kind, .. }) => {
|
||||
self.check_defaultness(item.span, *defaultness);
|
||||
if rhs.is_none() {
|
||||
if !rhs_kind.has_expr() {
|
||||
self.dcx().emit_err(errors::ConstWithoutBody {
|
||||
span: item.span,
|
||||
replace_span: self.ending_semi_or_hi(item.span),
|
||||
|
|
@ -1715,11 +1715,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
|
||||
if let AssocCtxt::Impl { .. } = ctxt {
|
||||
match &item.kind {
|
||||
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::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::Fn(box Fn { body, .. }) => {
|
||||
if body.is_none() && !self.is_sdylib_interface {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,6 @@
|
|||
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};
|
||||
|
|
@ -124,7 +125,7 @@ impl<'a> PostExpansionVisitor<'a> {
|
|||
&self,
|
||||
non_lifetime_binders,
|
||||
non_lt_param_spans,
|
||||
crate::fluent_generated::ast_passes_forbidden_non_lifetime_param
|
||||
msg!("only lifetime parameters can be used in this context")
|
||||
);
|
||||
|
||||
// FIXME(non_lifetime_binders): Const bound params are pretty broken.
|
||||
|
|
@ -248,6 +249,14 @@ 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");
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
|
@ -329,15 +338,11 @@ 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(_)) => {
|
||||
gate!(
|
||||
&self,
|
||||
try_blocks_heterogeneous,
|
||||
e.span,
|
||||
"`try bikeshed` expression is experimental"
|
||||
);
|
||||
// `try_blocks_heterogeneous` is new, and gated pre-expansion instead.
|
||||
}
|
||||
ast::ExprKind::Lit(token::Lit {
|
||||
kind: token::LitKind::Float | token::LitKind::Integer,
|
||||
|
|
@ -421,6 +426,20 @@ 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() {
|
||||
|
|
@ -440,6 +459,7 @@ 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 };
|
||||
|
|
@ -498,6 +518,7 @@ 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");
|
||||
|
|
@ -526,6 +547,27 @@ 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");
|
||||
|
|
@ -648,6 +690,27 @@ 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,11 +5,10 @@
|
|||
// 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,7 +1961,8 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
fn print_lifetime(&mut self, lifetime: ast::Lifetime) {
|
||||
self.print_name(lifetime.ident.name)
|
||||
self.word(lifetime.ident.name.to_string());
|
||||
self.ann_post(lifetime.ident)
|
||||
}
|
||||
|
||||
fn print_lifetime_bounds(&mut self, bounds: &ast::GenericBounds) {
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ impl<'a> State<'a> {
|
|||
ident,
|
||||
generics,
|
||||
ty,
|
||||
rhs,
|
||||
rhs_kind,
|
||||
define_opaque,
|
||||
}) => {
|
||||
self.print_item_const(
|
||||
|
|
@ -229,7 +229,7 @@ impl<'a> State<'a> {
|
|||
None,
|
||||
generics,
|
||||
ty,
|
||||
rhs.as_ref().map(|ct| ct.expr()),
|
||||
rhs_kind.expr(),
|
||||
&item.vis,
|
||||
ast::Safety::Default,
|
||||
*defaultness,
|
||||
|
|
@ -573,7 +573,7 @@ impl<'a> State<'a> {
|
|||
ident,
|
||||
generics,
|
||||
ty,
|
||||
rhs,
|
||||
rhs_kind,
|
||||
define_opaque,
|
||||
}) => {
|
||||
self.print_item_const(
|
||||
|
|
@ -581,7 +581,7 @@ impl<'a> State<'a> {
|
|||
None,
|
||||
generics,
|
||||
ty,
|
||||
rhs.as_ref().map(|ct| ct.expr()),
|
||||
rhs_kind.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" }
|
||||
|
|
|
|||
|
|
@ -1,246 +0,0 @@
|
|||
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: &'static [rustc_span::Symbol] = &[sym::unstable_feature_bound];
|
||||
const PATH: &[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::AllowConstFnUnstable(items, first_span);
|
||||
|items, first_span| AttributeKind::RustcAllowConstFnUnstable(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};
|
||||
use rustc_errors::{Applicability, PResult, msg};
|
||||
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};
|
||||
use rustc_parse::parser::{ForceCollect, Parser, Recovery};
|
||||
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, fluent_generated, parse_version, session_diagnostics};
|
||||
use crate::{AttributeParser, 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,
|
||||
fluent_generated::attr_parsing_unstable_cfg_target_compact,
|
||||
msg!("compact `cfg(target(..))` is experimental and subject to change"),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
|
@ -360,8 +360,10 @@ 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 { recover: true })?;
|
||||
let meta = MetaItemOrLitParser::parse_single(
|
||||
parser,
|
||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
|
||||
)?;
|
||||
let pred_span = pred_start.with_hi(parser.token.span.hi());
|
||||
|
||||
let cfg_predicate = AttributeParser::parse_single_args(
|
||||
|
|
@ -376,7 +378,7 @@ fn parse_cfg_attr_internal<'a>(
|
|||
CRATE_NODE_ID,
|
||||
Target::Crate,
|
||||
features,
|
||||
ShouldEmit::ErrorsAndLints { recover: true },
|
||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
|
||||
&meta,
|
||||
parse_cfg_entry,
|
||||
&CFG_ATTR_TEMPLATE,
|
||||
|
|
|
|||
|
|
@ -1,22 +1,35 @@
|
|||
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;
|
||||
use rustc_parse::parser::{Parser, Recovery};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::{ErrorGuaranteed, Span, sym};
|
||||
use rustc_session::lint::BuiltinLintDiag;
|
||||
use rustc_session::lint::builtin::UNREACHABLE_CFG_SELECT_PREDICATES;
|
||||
use rustc_span::{ErrorGuaranteed, Span, Symbol, 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.
|
||||
|
|
@ -78,9 +91,11 @@ pub fn parse_cfg_select(
|
|||
}
|
||||
}
|
||||
} else {
|
||||
let meta =
|
||||
MetaItemOrLitParser::parse_single(p, ShouldEmit::ErrorsAndLints { recover: true })
|
||||
.map_err(|diag| diag.emit())?;
|
||||
let meta = MetaItemOrLitParser::parse_single(
|
||||
p,
|
||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
|
||||
)
|
||||
.map_err(|diag| diag.emit())?;
|
||||
let cfg_span = meta.span();
|
||||
let cfg = AttributeParser::parse_single_args(
|
||||
sess,
|
||||
|
|
@ -95,7 +110,7 @@ pub fn parse_cfg_select(
|
|||
// Doesn't matter what the target actually is here.
|
||||
Target::Crate,
|
||||
features,
|
||||
ShouldEmit::ErrorsAndLints { recover: true },
|
||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
|
||||
&meta,
|
||||
parse_cfg_entry,
|
||||
&AttributeTemplate::default(),
|
||||
|
|
@ -113,5 +128,102 @@ 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::ObjcClass { classname, span: cx.attr_span })
|
||||
Some(AttributeKind::RustcObjcClass { 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::ObjcSelector { methname, span: cx.attr_span })
|
||||
Some(AttributeKind::RustcObjcSelector { methname, span: cx.attr_span })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ impl<S: Stage> AttributeParser<S> for ConfusablesParser {
|
|||
return None;
|
||||
}
|
||||
|
||||
Some(AttributeKind::Confusables {
|
||||
Some(AttributeKind::RustcConfusables {
|
||||
symbols: self.confusables,
|
||||
first_span: self.first_span.unwrap(),
|
||||
})
|
||||
|
|
|
|||
|
|
@ -274,3 +274,21 @@ impl<S: Stage> NoArgsAttributeParser<S> for NoBuiltinsParser {
|
|||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use rustc_hir::attrs::{DeprecatedSince, Deprecation};
|
||||
use rustc_hir::{RustcVersion, VERSION_PLACEHOLDER};
|
||||
|
||||
use super::prelude::*;
|
||||
use super::util::parse_version;
|
||||
|
|
@ -143,6 +144,8 @@ 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 {
|
||||
|
|
|
|||
|
|
@ -70,6 +70,42 @@ fn check_attr_crate_level<S: Stage>(cx: &mut AcceptContext<'_, '_, S>, span: Spa
|
|||
true
|
||||
}
|
||||
|
||||
// FIXME: To be removed once merged and replace with `cx.expected_name_value(span, _name)`.
|
||||
fn expected_name_value<S: Stage>(
|
||||
cx: &mut AcceptContext<'_, '_, S>,
|
||||
span: Span,
|
||||
_name: Option<Symbol>,
|
||||
) {
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
AttributeLintKind::ExpectedNameValue,
|
||||
span,
|
||||
);
|
||||
}
|
||||
|
||||
// FIXME: remove this method once merged and use `cx.expected_no_args(span)` instead.
|
||||
fn expected_no_args<S: Stage>(cx: &mut AcceptContext<'_, '_, S>, span: Span) {
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
AttributeLintKind::ExpectedNoArgs,
|
||||
span,
|
||||
);
|
||||
}
|
||||
|
||||
// FIXME: remove this method once merged and use `cx.expected_no_args(span)` instead.
|
||||
// cx.expected_string_literal(span, _actual_literal);
|
||||
fn expected_string_literal<S: Stage>(
|
||||
cx: &mut AcceptContext<'_, '_, S>,
|
||||
span: Span,
|
||||
_actual_literal: Option<&MetaItemLit>,
|
||||
) {
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
AttributeLintKind::MalformedDoc,
|
||||
span,
|
||||
);
|
||||
}
|
||||
|
||||
fn parse_keyword_and_attribute<S: Stage>(
|
||||
cx: &mut AcceptContext<'_, '_, S>,
|
||||
path: &OwnedPathParser,
|
||||
|
|
@ -78,12 +114,12 @@ fn parse_keyword_and_attribute<S: Stage>(
|
|||
attr_name: Symbol,
|
||||
) {
|
||||
let Some(nv) = args.name_value() else {
|
||||
cx.expected_name_value(args.span().unwrap_or(path.span()), path.word_sym());
|
||||
expected_name_value(cx, args.span().unwrap_or(path.span()), path.word_sym());
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(value) = nv.value_as_str() else {
|
||||
cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
|
||||
expected_string_literal(cx, nv.value_span, Some(nv.value_as_lit()));
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
@ -127,12 +163,21 @@ impl DocParser {
|
|||
match path.word_sym() {
|
||||
Some(sym::no_crate_inject) => {
|
||||
if let Err(span) = args.no_args() {
|
||||
cx.expected_no_args(span);
|
||||
expected_no_args(cx, span);
|
||||
return;
|
||||
}
|
||||
|
||||
if self.attribute.no_crate_inject.is_some() {
|
||||
cx.duplicate_key(path.span(), sym::no_crate_inject);
|
||||
if let Some(used_span) = self.attribute.no_crate_inject {
|
||||
let unused_span = path.span();
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
AttributeLintKind::UnusedDuplicate {
|
||||
this: unused_span,
|
||||
other: used_span,
|
||||
warning: true,
|
||||
},
|
||||
unused_span,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -144,7 +189,14 @@ impl DocParser {
|
|||
}
|
||||
Some(sym::attr) => {
|
||||
let Some(list) = args.list() else {
|
||||
cx.expected_list(cx.attr_span, args);
|
||||
// FIXME: remove this method once merged and uncomment the line below instead.
|
||||
// cx.expected_list(cx.attr_span, args);
|
||||
let span = cx.attr_span;
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
AttributeLintKind::MalformedDoc,
|
||||
span,
|
||||
);
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
@ -246,7 +298,7 @@ impl DocParser {
|
|||
inline: DocInline,
|
||||
) {
|
||||
if let Err(span) = args.no_args() {
|
||||
cx.expected_no_args(span);
|
||||
expected_no_args(cx, span);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -328,7 +380,14 @@ impl DocParser {
|
|||
match sub_item.args() {
|
||||
a @ (ArgParser::NoArgs | ArgParser::NameValue(_)) => {
|
||||
let Some(name) = sub_item.path().word_sym() else {
|
||||
cx.expected_identifier(sub_item.path().span());
|
||||
// FIXME: remove this method once merged and uncomment the line
|
||||
// below instead.
|
||||
// cx.expected_identifier(sub_item.path().span());
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
AttributeLintKind::MalformedDoc,
|
||||
sub_item.path().span(),
|
||||
);
|
||||
continue;
|
||||
};
|
||||
if let Ok(CfgEntry::NameValue { name, value, .. }) =
|
||||
|
|
@ -391,7 +450,7 @@ impl DocParser {
|
|||
macro_rules! no_args {
|
||||
($ident: ident) => {{
|
||||
if let Err(span) = args.no_args() {
|
||||
cx.expected_no_args(span);
|
||||
expected_no_args(cx, span);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -410,7 +469,7 @@ impl DocParser {
|
|||
macro_rules! no_args_and_not_crate_level {
|
||||
($ident: ident) => {{
|
||||
if let Err(span) = args.no_args() {
|
||||
cx.expected_no_args(span);
|
||||
expected_no_args(cx, span);
|
||||
return;
|
||||
}
|
||||
let span = path.span();
|
||||
|
|
@ -423,7 +482,7 @@ impl DocParser {
|
|||
macro_rules! no_args_and_crate_level {
|
||||
($ident: ident) => {{
|
||||
if let Err(span) = args.no_args() {
|
||||
cx.expected_no_args(span);
|
||||
expected_no_args(cx, span);
|
||||
return;
|
||||
}
|
||||
let span = path.span();
|
||||
|
|
@ -436,12 +495,12 @@ impl DocParser {
|
|||
macro_rules! string_arg_and_crate_level {
|
||||
($ident: ident) => {{
|
||||
let Some(nv) = args.name_value() else {
|
||||
cx.expected_name_value(args.span().unwrap_or(path.span()), path.word_sym());
|
||||
expected_name_value(cx, args.span().unwrap_or(path.span()), path.word_sym());
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(s) = nv.value_as_str() else {
|
||||
cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
|
||||
expected_string_literal(cx, nv.value_span, Some(nv.value_as_lit()));
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
@ -512,7 +571,14 @@ impl DocParser {
|
|||
self.parse_single_test_doc_attr_item(cx, mip);
|
||||
}
|
||||
MetaItemOrLitParser::Lit(lit) => {
|
||||
cx.unexpected_literal(lit.span);
|
||||
// FIXME: remove this method once merged and uncomment the line
|
||||
// below instead.
|
||||
// cx.unexpected_literal(lit.span);
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
AttributeLintKind::MalformedDoc,
|
||||
lit.span,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -582,7 +648,7 @@ impl DocParser {
|
|||
let suggestions = cx.suggestions();
|
||||
let span = cx.attr_span;
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT,
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
AttributeLintKind::IllFormedAttributeInput { suggestions, docs: None },
|
||||
span,
|
||||
);
|
||||
|
|
@ -595,14 +661,14 @@ impl DocParser {
|
|||
self.parse_single_doc_attr_item(cx, mip);
|
||||
}
|
||||
MetaItemOrLitParser::Lit(lit) => {
|
||||
cx.expected_name_value(lit.span, None);
|
||||
expected_name_value(cx, lit.span, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ArgParser::NameValue(nv) => {
|
||||
if nv.value_as_str().is_none() {
|
||||
cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
|
||||
expected_string_literal(cx, nv.value_span, Some(nv.value_as_lit()));
|
||||
} else {
|
||||
unreachable!(
|
||||
"Should have been handled at the same time as sugar-syntaxed doc comments"
|
||||
|
|
|
|||
|
|
@ -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::Dummy)
|
||||
Some(AttributeKind::RustcDummy)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use super::prelude::*;
|
|||
pub(crate) struct InlineParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for InlineParser {
|
||||
const PATH: &'static [Symbol] = &[sym::inline];
|
||||
const PATH: &[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: &'static [Symbol] = &[sym::rustc_force_inline];
|
||||
const PATH: &[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,3 +1,4 @@
|
|||
use rustc_errors::msg;
|
||||
use rustc_feature::Features;
|
||||
use rustc_hir::attrs::AttributeKind::{LinkName, LinkOrdinal, LinkSection};
|
||||
use rustc_hir::attrs::*;
|
||||
|
|
@ -10,12 +11,11 @@ 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, ImportNameTypeRaw, ImportNameTypeX86,
|
||||
IncompatibleWasmLink, InvalidLinkModifier, LinkFrameworkApple, LinkOrdinalOutOfRange,
|
||||
LinkRequiresName, MultipleModifiers, NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows,
|
||||
WholeArchiveNeedsStatic,
|
||||
AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ExportSymbolsNeedsStatic,
|
||||
ImportNameTypeRaw, ImportNameTypeX86, IncompatibleWasmLink, InvalidLinkModifier,
|
||||
LinkFrameworkApple, LinkOrdinalOutOfRange, LinkRequiresName, MultipleModifiers,
|
||||
NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows, WholeArchiveNeedsStatic,
|
||||
};
|
||||
|
||||
pub(crate) struct LinkNameParser;
|
||||
|
|
@ -165,6 +165,14 @@ 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),
|
||||
|
||||
(
|
||||
|
|
@ -190,6 +198,7 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
|
|||
span,
|
||||
&[
|
||||
sym::bundle,
|
||||
sym::export_symbols,
|
||||
sym::verbatim,
|
||||
sym::whole_dash_archive,
|
||||
sym::as_dash_needed,
|
||||
|
|
@ -285,7 +294,9 @@ impl LinkParser {
|
|||
};
|
||||
|
||||
let link_kind = match link_kind {
|
||||
kw::Static => NativeLibKind::Static { bundle: None, whole_archive: None },
|
||||
kw::Static => {
|
||||
NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None }
|
||||
}
|
||||
sym::dylib => NativeLibKind::Dylib { as_needed: None },
|
||||
sym::framework => {
|
||||
if !sess.target.is_like_darwin {
|
||||
|
|
@ -305,7 +316,7 @@ impl LinkParser {
|
|||
sess,
|
||||
sym::raw_dylib_elf,
|
||||
nv.value_span,
|
||||
fluent_generated::attr_parsing_raw_dylib_elf_unstable,
|
||||
msg!("link kind `raw-dylib` is unstable on ELF platforms"),
|
||||
)
|
||||
.emit();
|
||||
} else {
|
||||
|
|
@ -320,7 +331,7 @@ impl LinkParser {
|
|||
sess,
|
||||
sym::link_arg_attribute,
|
||||
nv.value_span,
|
||||
fluent_generated::attr_parsing_link_arg_unstable,
|
||||
msg!("link kind `link-arg` is unstable"),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
|
@ -385,13 +396,7 @@ impl LinkParser {
|
|||
return true;
|
||||
};
|
||||
if !features.link_cfg() {
|
||||
feature_err(
|
||||
sess,
|
||||
sym::link_cfg,
|
||||
item.span(),
|
||||
fluent_generated::attr_parsing_link_cfg_unstable,
|
||||
)
|
||||
.emit();
|
||||
feature_err(sess, sym::link_cfg, item.span(), msg!("link cfg is unstable")).emit();
|
||||
}
|
||||
*cfg = parse_cfg_entry(cx, link_cfg).ok();
|
||||
true
|
||||
|
|
@ -529,7 +534,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for StdInternalSymbolParser {
|
|||
Allow(Target::Static),
|
||||
Allow(Target::ForeignStatic),
|
||||
]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::StdInternalSymbol;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcStdInternalSymbol;
|
||||
}
|
||||
|
||||
pub(crate) struct LinkOrdinalParser;
|
||||
|
|
|
|||
|
|
@ -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::AsPtr;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcAsPtr;
|
||||
}
|
||||
|
||||
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::PubTransparent;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPubTransparent;
|
||||
}
|
||||
|
||||
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::PassByValue;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassByValue;
|
||||
}
|
||||
|
||||
pub(crate) struct RustcShouldNotBeCalledOnConstItems;
|
||||
|
|
|
|||
|
|
@ -206,3 +206,12 @@ 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_session::lint::builtin::AMBIGUOUS_DERIVE_HELPERS;
|
||||
|
||||
use super::prelude::*;
|
||||
|
||||
const PROC_MACRO_ALLOWED_TARGETS: AllowedTargets =
|
||||
|
|
@ -126,6 +129,13 @@ 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: &'static [Symbol] = &[sym::rustc_align];
|
||||
const PATH: &[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: &'static [Symbol] = &[sym::rustc_align_static];
|
||||
const PATH: &[Symbol] = &[sym::rustc_align_static];
|
||||
const TEMPLATE: AttributeTemplate = AlignParser::TEMPLATE;
|
||||
|
||||
fn parse<S: Stage>(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) {
|
||||
|
|
|
|||
|
|
@ -7,36 +7,36 @@ use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
|
|||
use crate::context::Stage;
|
||||
use crate::target_checking::AllowedTargets;
|
||||
|
||||
pub(crate) struct RustcDumpUserArgs;
|
||||
pub(crate) struct RustcDumpUserArgsParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpUserArgs {
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpUserArgsParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_dump_user_args];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpUserArgs;
|
||||
}
|
||||
|
||||
pub(crate) struct RustcDumpDefParents;
|
||||
pub(crate) struct RustcDumpDefParentsParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpDefParents {
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpDefParentsParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_dump_def_parents];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpDefParents;
|
||||
}
|
||||
|
||||
pub(crate) struct RustcDumpItemBounds;
|
||||
pub(crate) struct RustcDumpItemBoundsParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpItemBounds {
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpItemBoundsParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_dump_item_bounds];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::AssocTy)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpItemBounds;
|
||||
}
|
||||
|
||||
pub(crate) struct RustcDumpPredicates;
|
||||
pub(crate) struct RustcDumpPredicatesParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpPredicates {
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpPredicatesParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_dump_predicates];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
|
|
@ -49,9 +49,9 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpPredicates {
|
|||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpPredicates;
|
||||
}
|
||||
|
||||
pub(crate) struct RustcDumpVtable;
|
||||
pub(crate) struct RustcDumpVtableParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpVtable {
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpVtableParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_dump_vtable];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
|
|
|
|||
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::BodyStability { stability, span })
|
||||
Some(AttributeKind::RustcBodyStability { 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::ConstStabilityIndirect;
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcConstStabilityIndirect;
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
@ -244,7 +244,20 @@ impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
|
|||
this.promotable = true;
|
||||
}),
|
||||
];
|
||||
const ALLOWED_TARGETS: AllowedTargets = ALLOWED_TARGETS;
|
||||
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),
|
||||
]);
|
||||
|
||||
fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
if self.promotable {
|
||||
|
|
@ -258,7 +271,7 @@ impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
|
|||
|
||||
let (stability, span) = self.stability?;
|
||||
|
||||
Some(AttributeKind::ConstStability { stability, span })
|
||||
Some(AttributeKind::RustcConstStability { stability, span })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use rustc_hir::attrs::RustcAbiAttrKind;
|
||||
use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
|
||||
|
||||
use super::prelude::*;
|
||||
|
|
@ -113,3 +114,179 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcVarianceOfOpaquesParser {
|
|||
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,7 +50,11 @@ impl<S: Stage> SingleAttributeParser<S> for SkipDuringMethodDispatchParser {
|
|||
cx.duplicate_key(arg.span(), key);
|
||||
}
|
||||
}
|
||||
Some(AttributeKind::SkipDuringMethodDispatch { array, boxed_slice, span: cx.attr_span })
|
||||
Some(AttributeKind::RustcSkipDuringMethodDispatch {
|
||||
array,
|
||||
boxed_slice,
|
||||
span: cx.attr_span,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -59,16 +63,7 @@ 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::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;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcParenSugar;
|
||||
}
|
||||
|
||||
// Markers
|
||||
|
|
@ -91,7 +86,7 @@ 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::DenyExplicitImpl;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcDenyExplicitImpl;
|
||||
}
|
||||
|
||||
pub(crate) struct DynIncompatibleTraitParser;
|
||||
|
|
@ -99,7 +94,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for DynIncompatibleTraitParser {
|
|||
const PATH: &[Symbol] = &[sym::rustc_dyn_incompatible_trait];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::DynIncompatibleTrait;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcDynIncompatibleTrait;
|
||||
}
|
||||
|
||||
// Specialization
|
||||
|
|
@ -109,7 +104,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::SpecializationTrait;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcSpecializationTrait;
|
||||
}
|
||||
|
||||
pub(crate) struct UnsafeSpecializationMarkerParser;
|
||||
|
|
@ -117,7 +112,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::UnsafeSpecializationMarker;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcUnsafeSpecializationMarker;
|
||||
}
|
||||
|
||||
// Coherence
|
||||
|
|
@ -127,7 +122,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::Coinductive;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcCoinductive;
|
||||
}
|
||||
|
||||
pub(crate) struct AllowIncoherentImplParser;
|
||||
|
|
@ -136,7 +131,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::AllowIncoherentImpl;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcAllowIncoherentImpl;
|
||||
}
|
||||
|
||||
pub(crate) struct FundamentalParser;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,6 @@ impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
|
|||
}
|
||||
None => None,
|
||||
}
|
||||
.map(AttributeKind::MacroTransparency)
|
||||
.map(AttributeKind::RustcMacroTransparency)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::cell::RefCell;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::btree_map::Entry;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::LazyLock;
|
||||
|
||||
|
|
@ -10,93 +11,48 @@ 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;
|
||||
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,
|
||||
PatchableFunctionEntryParser, RustcPassIndirectlyInNonRusticAbisParser, SanitizeParser,
|
||||
TargetFeatureParser, ThreadLocalParser, TrackCallerParser, UsedParser,
|
||||
};
|
||||
use crate::attributes::confusables::ConfusablesParser;
|
||||
use crate::attributes::crate_level::{
|
||||
CrateNameParser, CrateTypeParser, MoveSizeLimitParser, NeedsPanicRuntimeParser,
|
||||
NoBuiltinsParser, NoCoreParser, NoMainParser, NoStdParser, PanicRuntimeParser,
|
||||
PatternComplexityLimitParser, ProfilerRuntimeParser, RecursionLimitParser,
|
||||
RustcCoherenceIsCoreParser, TypeLengthLimitParser, WindowsSubsystemParser,
|
||||
};
|
||||
use crate::attributes::debugger::DebuggerViualizerParser;
|
||||
use crate::attributes::deprecation::DeprecationParser;
|
||||
use crate::attributes::do_not_recommend::DoNotRecommendParser;
|
||||
use crate::attributes::doc::DocParser;
|
||||
use crate::attributes::dummy::DummyParser;
|
||||
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
|
||||
use crate::attributes::instruction_set::InstructionSetParser;
|
||||
use crate::attributes::link_attrs::{
|
||||
CompilerBuiltinsParser, ExportStableParser, FfiConstParser, FfiPureParser, LinkNameParser,
|
||||
LinkOrdinalParser, LinkParser, LinkSectionParser, LinkageParser, NeedsAllocatorParser,
|
||||
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;
|
||||
// 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::path::PathParser as PathAttributeParser;
|
||||
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_allocator::{
|
||||
RustcAllocatorParser, RustcAllocatorZeroedParser, RustcAllocatorZeroedVariantParser,
|
||||
RustcDeallocatorParser, RustcReallocatorParser,
|
||||
};
|
||||
use crate::attributes::rustc_dump::{
|
||||
RustcDumpDefParents, RustcDumpItemBounds, RustcDumpPredicates, RustcDumpUserArgs,
|
||||
RustcDumpVtable,
|
||||
};
|
||||
use crate::attributes::rustc_internal::{
|
||||
RustcHasIncoherentInherentImplsParser, RustcLayoutScalarValidRangeEndParser,
|
||||
RustcLayoutScalarValidRangeStartParser, RustcLegacyConstGenericsParser,
|
||||
RustcLintOptDenyFieldAccessParser, RustcLintOptTyParser, RustcLintQueryInstabilityParser,
|
||||
RustcLintUntrackedQueryInformationParser, RustcMainParser, RustcMustImplementOneOfParser,
|
||||
RustcNeverReturnsNullPointerParser, RustcNoImplicitAutorefsParser, RustcNounwindParser,
|
||||
RustcObjectLifetimeDefaultParser, RustcOffloadKernelParser, RustcScalableVectorParser,
|
||||
RustcSimdMonomorphizeLaneLimitParser,
|
||||
};
|
||||
use crate::attributes::semantics::MayDangleParser;
|
||||
use crate::attributes::stability::{
|
||||
BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
|
||||
};
|
||||
use crate::attributes::test_attrs::{
|
||||
IgnoreParser, RustcVarianceOfOpaquesParser, RustcVarianceParser, ShouldPanicParser,
|
||||
};
|
||||
use crate::attributes::traits::{
|
||||
AllowIncoherentImplParser, CoinductiveParser, DenyExplicitImplParser,
|
||||
DynIncompatibleTraitParser, FundamentalParser, MarkerParser, ParenSugarParser, PointeeParser,
|
||||
SkipDuringMethodDispatchParser, SpecializationTraitParser, TypeConstParser,
|
||||
UnsafeSpecializationMarkerParser,
|
||||
};
|
||||
use crate::attributes::transparency::TransparencyParser;
|
||||
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::{AttributeParser as _, Combine, Single, WithoutArgs};
|
||||
use crate::parser::{ArgParser, RefPathParser};
|
||||
use crate::session_diagnostics::{
|
||||
|
|
@ -106,7 +62,7 @@ use crate::target_checking::AllowedTargets;
|
|||
type GroupType<S> = LazyLock<GroupTypeInner<S>>;
|
||||
|
||||
pub(super) struct GroupTypeInner<S: Stage> {
|
||||
pub(super) accepters: BTreeMap<&'static [Symbol], Vec<GroupTypeInnerAccept<S>>>,
|
||||
pub(super) accepters: BTreeMap<&'static [Symbol], GroupTypeInnerAccept<S>>,
|
||||
}
|
||||
|
||||
pub(super) struct GroupTypeInnerAccept<S: Stage> {
|
||||
|
|
@ -146,7 +102,7 @@ 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::<_, Vec<GroupTypeInnerAccept<$stage>>>::new();
|
||||
let mut accepters = BTreeMap::<_, GroupTypeInnerAccept<$stage>>::new();
|
||||
$(
|
||||
{
|
||||
thread_local! {
|
||||
|
|
@ -154,19 +110,24 @@ macro_rules! attribute_parsers {
|
|||
};
|
||||
|
||||
for (path, template, accept_fn) in <$names>::ATTRIBUTES {
|
||||
accepters.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,
|
||||
finalizer: Box::new(|cx| {
|
||||
let state = STATE_OBJECT.take();
|
||||
state.finalize(cx)
|
||||
}),
|
||||
});
|
||||
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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
)*
|
||||
|
|
@ -186,6 +147,7 @@ attribute_parsers!(
|
|||
DocParser,
|
||||
MacroUseParser,
|
||||
NakedParser,
|
||||
RustcCguTestAttributeParser,
|
||||
StabilityParser,
|
||||
UsedParser,
|
||||
// tidy-alphabetical-end
|
||||
|
|
@ -198,6 +160,10 @@ attribute_parsers!(
|
|||
Combine<ForceTargetFeatureParser>,
|
||||
Combine<LinkParser>,
|
||||
Combine<ReprParser>,
|
||||
Combine<RustcCleanParser>,
|
||||
Combine<RustcLayoutParser>,
|
||||
Combine<RustcMirParser>,
|
||||
Combine<RustcThenThisWouldNeedParser>,
|
||||
Combine<TargetFeatureParser>,
|
||||
Combine<UnstableFeatureBoundParser>,
|
||||
// tidy-alphabetical-end
|
||||
|
|
@ -215,6 +181,7 @@ attribute_parsers!(
|
|||
Single<IgnoreParser>,
|
||||
Single<InlineParser>,
|
||||
Single<InstructionSetParser>,
|
||||
Single<LangParser>,
|
||||
Single<LinkNameParser>,
|
||||
Single<LinkOrdinalParser>,
|
||||
Single<LinkSectionParser>,
|
||||
|
|
@ -231,20 +198,30 @@ attribute_parsers!(
|
|||
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<RustcObjectLifetimeDefaultParser>,
|
||||
Single<RustcNeverTypeOptionsParser>,
|
||||
Single<RustcReservationImplParser>,
|
||||
Single<RustcScalableVectorParser>,
|
||||
Single<RustcSimdMonomorphizeLaneLimitParser>,
|
||||
Single<RustcSymbolName>,
|
||||
Single<RustcTestMarkerParser>,
|
||||
Single<SanitizeParser>,
|
||||
Single<ShouldPanicParser>,
|
||||
Single<SkipDuringMethodDispatchParser>,
|
||||
Single<TestRunnerParser>,
|
||||
Single<TransparencyParser>,
|
||||
Single<TypeLengthLimitParser>,
|
||||
Single<WindowsSubsystemParser>,
|
||||
|
|
@ -279,43 +256,63 @@ attribute_parsers!(
|
|||
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<RustcDumpDefParents>>,
|
||||
Single<WithoutArgs<RustcDumpItemBounds>>,
|
||||
Single<WithoutArgs<RustcDumpPredicates>>,
|
||||
Single<WithoutArgs<RustcDumpUserArgs>>,
|
||||
Single<WithoutArgs<RustcDumpVtable>>,
|
||||
Single<WithoutArgs<RustcDelayedBugFromInsideQueryParser>>,
|
||||
Single<WithoutArgs<RustcDumpDefParentsParser>>,
|
||||
Single<WithoutArgs<RustcDumpItemBoundsParser>>,
|
||||
Single<WithoutArgs<RustcDumpPredicatesParser>>,
|
||||
Single<WithoutArgs<RustcDumpUserArgsParser>>,
|
||||
Single<WithoutArgs<RustcDumpVtableParser>>,
|
||||
Single<WithoutArgs<RustcEffectiveVisibilityParser>>,
|
||||
Single<WithoutArgs<RustcEvaluateWhereClausesParser>>,
|
||||
Single<WithoutArgs<RustcHasIncoherentInherentImplsParser>>,
|
||||
Single<WithoutArgs<RustcHiddenTypeOfOpaquesParser>>,
|
||||
Single<WithoutArgs<RustcInsignificantDtorParser>>,
|
||||
Single<WithoutArgs<RustcIntrinsicConstStableIndirectParser>>,
|
||||
Single<WithoutArgs<RustcIntrinsicParser>>,
|
||||
Single<WithoutArgs<RustcLintOptTyParser>>,
|
||||
Single<WithoutArgs<RustcLintQueryInstabilityParser>>,
|
||||
Single<WithoutArgs<RustcLintUntrackedQueryInformationParser>>,
|
||||
Single<WithoutArgs<RustcMainParser>>,
|
||||
Single<WithoutArgs<RustcNeverReturnsNullPointerParser>>,
|
||||
Single<WithoutArgs<RustcNoImplicitAutorefsParser>>,
|
||||
Single<WithoutArgs<RustcNoImplicitBoundsParser>>,
|
||||
Single<WithoutArgs<RustcNoMirInlineParser>>,
|
||||
Single<WithoutArgs<RustcNonConstTraitMethodParser>>,
|
||||
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 +378,7 @@ impl Stage for Late {
|
|||
}
|
||||
|
||||
fn should_emit(&self) -> ShouldEmit {
|
||||
ShouldEmit::ErrorsAndLints { recover: true }
|
||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -510,6 +507,11 @@ 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)
|
||||
}
|
||||
|
|
@ -768,10 +770,10 @@ pub enum ShouldEmit {
|
|||
ErrorsAndLints {
|
||||
/// Whether [`ArgParser`] will attempt to recover from errors.
|
||||
///
|
||||
/// If true, it will attempt to recover from bad input (like an invalid literal). Setting
|
||||
/// this to false will instead return early, and not raise errors except at the top level
|
||||
/// (in [`ArgParser::from_attr_args`]).
|
||||
recover: bool,
|
||||
/// 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.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -327,7 +327,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(accepts) = S::parsers().accepters.get(parts.as_slice()) {
|
||||
if let Some(accept) = S::parsers().accepters.get(parts.as_slice()) {
|
||||
let Some(args) = ArgParser::from_attr_args(
|
||||
args,
|
||||
&parts,
|
||||
|
|
@ -368,28 +368,26 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
continue;
|
||||
}
|
||||
|
||||
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(),
|
||||
};
|
||||
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);
|
||||
(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);
|
||||
}
|
||||
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
|
||||
|
|
|
|||
|
|
@ -113,5 +113,3 @@ 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,7 +15,7 @@ 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, token_descr};
|
||||
use rustc_parse::parser::{ForceCollect, Parser, PathStyle, Recovery, token_descr};
|
||||
use rustc_session::errors::create_lit_error;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::{Ident, Span, Symbol, sym};
|
||||
|
|
@ -121,7 +121,7 @@ impl ArgParser {
|
|||
&args.tokens,
|
||||
args.dspan.entire(),
|
||||
psess,
|
||||
ShouldEmit::ErrorsAndLints { recover: false },
|
||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden },
|
||||
) {
|
||||
Ok(p) => return Some(ArgParser::List(p)),
|
||||
Err(e) => {
|
||||
|
|
@ -373,7 +373,10 @@ fn expr_to_lit<'sess>(
|
|||
}
|
||||
Err(err) => {
|
||||
let err = create_lit_error(psess, err, token_lit, expr.span);
|
||||
if matches!(should_emit, ShouldEmit::ErrorsAndLints { recover: false }) {
|
||||
if matches!(
|
||||
should_emit,
|
||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden }
|
||||
) {
|
||||
Err(err)
|
||||
} else {
|
||||
let lit = MetaItemLit {
|
||||
|
|
@ -431,7 +434,10 @@ 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 { recover: false }) {
|
||||
if matches!(
|
||||
self.should_emit,
|
||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden }
|
||||
) {
|
||||
return Err(err);
|
||||
} else {
|
||||
self.should_emit.emit_err(err)
|
||||
|
|
@ -569,6 +575,10 @@ 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,10 +11,8 @@ use rustc_macros::{Diagnostic, Subdiagnostic};
|
|||
use rustc_span::{Span, Symbol};
|
||||
use rustc_target::spec::TargetTuple;
|
||||
|
||||
use crate::fluent_generated as fluent;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_invalid_predicate, code = E0537)]
|
||||
#[diag("invalid predicate `{$predicate}`", code = E0537)]
|
||||
pub(crate) struct InvalidPredicate {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -23,7 +21,7 @@ pub(crate) struct InvalidPredicate {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_doc_alias_empty)]
|
||||
#[diag("{$attr_str} attribute cannot have empty value")]
|
||||
pub(crate) struct DocAliasEmpty<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -31,7 +29,7 @@ pub(crate) struct DocAliasEmpty<'a> {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_doc_alias_bad_char)]
|
||||
#[diag("{$char_} character isn't allowed in {$attr_str}")]
|
||||
pub(crate) struct DocAliasBadChar<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -40,7 +38,7 @@ pub(crate) struct DocAliasBadChar<'a> {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_doc_alias_start_end)]
|
||||
#[diag("{$attr_str} cannot start or end with ' '")]
|
||||
pub(crate) struct DocAliasStartEnd<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -48,7 +46,16 @@ pub(crate) struct DocAliasStartEnd<'a> {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_doc_attr_not_crate_level)]
|
||||
#[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")]
|
||||
pub(crate) struct DocAttrNotCrateLevel {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -56,8 +63,8 @@ pub(crate) struct DocAttrNotCrateLevel {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_doc_keyword_not_keyword)]
|
||||
#[help]
|
||||
#[diag("nonexistent keyword `{$keyword}` used in `#[doc(keyword = \"...\")]`")]
|
||||
#[help("only existing keywords are allowed in core/std")]
|
||||
pub(crate) struct DocKeywordNotKeyword {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -65,8 +72,8 @@ pub(crate) struct DocKeywordNotKeyword {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_doc_attribute_not_attribute)]
|
||||
#[help]
|
||||
#[diag("nonexistent builtin attribute `{$attribute}` used in `#[doc(attribute = \"...\")]`")]
|
||||
#[help("only existing builtin attributes are allowed in core/std")]
|
||||
pub(crate) struct DocAttributeNotAttribute {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -74,28 +81,28 @@ pub(crate) struct DocAttributeNotAttribute {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_missing_since, code = E0542)]
|
||||
#[diag("missing 'since'", code = E0542)]
|
||||
pub(crate) struct MissingSince {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_missing_note, code = E0543)]
|
||||
#[diag("missing 'note'", code = E0543)]
|
||||
pub(crate) struct MissingNote {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_multiple_stability_levels, code = E0544)]
|
||||
#[diag("multiple stability levels", code = E0544)]
|
||||
pub(crate) struct MultipleStabilityLevels {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_invalid_issue_string, code = E0545)]
|
||||
#[diag("`issue` must be a non-zero numeric string or \"none\"", code = E0545)]
|
||||
pub(crate) struct InvalidIssueString {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -108,31 +115,31 @@ pub(crate) struct InvalidIssueString {
|
|||
// translatable.
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum InvalidIssueStringCause {
|
||||
#[label(attr_parsing_must_not_be_zero)]
|
||||
#[label("`issue` must not be \"0\", use \"none\" instead")]
|
||||
MustNotBeZero {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
|
||||
#[label(attr_parsing_empty)]
|
||||
#[label("cannot parse integer from empty string")]
|
||||
Empty {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
|
||||
#[label(attr_parsing_invalid_digit)]
|
||||
#[label("invalid digit found in string")]
|
||||
InvalidDigit {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
|
||||
#[label(attr_parsing_pos_overflow)]
|
||||
#[label("number too large to fit in target type")]
|
||||
PosOverflow {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
|
||||
#[label(attr_parsing_neg_overflow)]
|
||||
#[label("number too small to fit in target type")]
|
||||
NegOverflow {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
|
|
@ -153,21 +160,21 @@ impl InvalidIssueStringCause {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_missing_feature, code = E0546)]
|
||||
#[diag("missing 'feature'", code = E0546)]
|
||||
pub(crate) struct MissingFeature {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_non_ident_feature, code = E0546)]
|
||||
#[diag("'feature' is not an identifier", code = E0546)]
|
||||
pub(crate) struct NonIdentFeature {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_missing_issue, code = E0547)]
|
||||
#[diag("missing 'issue'", code = E0547)]
|
||||
pub(crate) struct MissingIssue {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -176,20 +183,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(attr_parsing_incorrect_repr_format_packed_one_or_zero_arg, code = E0552)]
|
||||
#[diag("incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all", code = E0552)]
|
||||
pub(crate) struct IncorrectReprFormatPackedOneOrZeroArg {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_incorrect_repr_format_packed_expect_integer, code = E0552)]
|
||||
#[diag("incorrect `repr(packed)` attribute format: `packed` expects a literal integer as argument", code = E0552)]
|
||||
pub(crate) struct IncorrectReprFormatPackedExpectInteger {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_invalid_repr_hint_no_paren, code = E0552)]
|
||||
#[diag("invalid representation hint: `{$name}` does not take a parenthesized argument list", code = E0552)]
|
||||
pub(crate) struct InvalidReprHintNoParen {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -198,7 +205,7 @@ pub(crate) struct InvalidReprHintNoParen {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_invalid_repr_hint_no_value, code = E0552)]
|
||||
#[diag("invalid representation hint: `{$name}` does not take a value", code = E0552)]
|
||||
pub(crate) struct InvalidReprHintNoValue {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -207,15 +214,19 @@ pub(crate) struct InvalidReprHintNoValue {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_invalid_repr_align_need_arg, code = E0589)]
|
||||
#[diag("invalid `repr(align)` attribute: `align` needs an argument", code = E0589)]
|
||||
pub(crate) struct InvalidReprAlignNeedArg {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "align(...)", applicability = "has-placeholders")]
|
||||
#[suggestion(
|
||||
"supply an argument here",
|
||||
code = "align(...)",
|
||||
applicability = "has-placeholders"
|
||||
)]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_invalid_repr_generic, code = E0589)]
|
||||
#[diag("invalid `repr({$repr_arg})` attribute: {$error_part}", code = E0589)]
|
||||
pub(crate) struct InvalidReprGeneric<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -225,21 +236,21 @@ pub(crate) struct InvalidReprGeneric<'a> {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_incorrect_repr_format_align_one_arg, code = E0693)]
|
||||
#[diag("incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses", code = E0693)]
|
||||
pub(crate) struct IncorrectReprFormatAlignOneArg {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_incorrect_repr_format_expect_literal_integer, code = E0693)]
|
||||
#[diag("incorrect `repr(align)` attribute format: `align` expects a literal integer as argument", code = E0693)]
|
||||
pub(crate) struct IncorrectReprFormatExpectInteger {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_incorrect_repr_format_generic, code = E0693)]
|
||||
#[diag("incorrect `repr({$repr_arg})` attribute format", code = E0693)]
|
||||
pub(crate) struct IncorrectReprFormatGeneric {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -253,7 +264,7 @@ pub(crate) struct IncorrectReprFormatGeneric {
|
|||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum IncorrectReprFormatGenericCause {
|
||||
#[suggestion(
|
||||
attr_parsing_suggestion,
|
||||
"use parentheses instead",
|
||||
code = "{name}({value})",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
|
|
@ -269,7 +280,7 @@ pub(crate) enum IncorrectReprFormatGenericCause {
|
|||
},
|
||||
|
||||
#[suggestion(
|
||||
attr_parsing_suggestion,
|
||||
"use parentheses instead",
|
||||
code = "{name}({value})",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
|
|
@ -298,48 +309,48 @@ impl IncorrectReprFormatGenericCause {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_rustc_promotable_pairing, code = E0717)]
|
||||
#[diag("`rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute", code = E0717)]
|
||||
pub(crate) struct RustcPromotablePairing {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_rustc_allowed_unstable_pairing, code = E0789)]
|
||||
#[diag("`rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute", code = E0789)]
|
||||
pub(crate) struct RustcAllowedUnstablePairing {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_deprecated_item_suggestion)]
|
||||
#[diag("suggestions on deprecated items are unstable")]
|
||||
pub(crate) struct DeprecatedItemSuggestion {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
||||
#[help]
|
||||
#[help("add `#![feature(deprecated_suggestion)]` to the crate root")]
|
||||
pub is_nightly: bool,
|
||||
|
||||
#[note]
|
||||
#[note("see #94785 for more details")]
|
||||
pub details: (),
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_expected_single_version_literal)]
|
||||
#[diag("expected single version literal")]
|
||||
pub(crate) struct ExpectedSingleVersionLiteral {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_expected_version_literal)]
|
||||
#[diag("expected a version literal")]
|
||||
pub(crate) struct ExpectedVersionLiteral {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_expects_feature_list)]
|
||||
#[diag("`{$name}` expects a list of feature names")]
|
||||
pub(crate) struct ExpectsFeatureList {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -348,7 +359,7 @@ pub(crate) struct ExpectsFeatureList {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_expects_features)]
|
||||
#[diag("`{$name}` expects feature names")]
|
||||
pub(crate) struct ExpectsFeatures {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -357,21 +368,21 @@ pub(crate) struct ExpectsFeatures {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_invalid_since)]
|
||||
#[diag("'since' must be a Rust version number, such as \"1.31.0\"")]
|
||||
pub(crate) struct InvalidSince {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_soft_no_args)]
|
||||
#[diag("`soft` should not have any arguments")]
|
||||
pub(crate) struct SoftNoArgs {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_unknown_version_literal)]
|
||||
#[diag("unknown version literal format, assuming it refers to a future version")]
|
||||
pub(crate) struct UnknownVersionLiteral {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -379,78 +390,83 @@ pub(crate) struct UnknownVersionLiteral {
|
|||
|
||||
// FIXME(jdonszelmann) duplicated from `rustc_passes`, remove once `check_attr` is integrated.
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_unused_multiple)]
|
||||
#[diag("multiple `{$name}` attributes")]
|
||||
pub(crate) struct UnusedMultiple {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||
#[suggestion("remove this attribute", code = "", applicability = "machine-applicable")]
|
||||
pub this: Span,
|
||||
#[note]
|
||||
#[note("attribute also specified here")]
|
||||
pub other: Span,
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_null_on_export, code = E0648)]
|
||||
#[diag("`export_name` may not contain null characters", code = E0648)]
|
||||
pub(crate) struct NullOnExport {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_null_on_link_section, code = E0648)]
|
||||
#[diag("`link_section` may not contain null characters", code = E0648)]
|
||||
pub(crate) struct NullOnLinkSection {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_null_on_objc_class)]
|
||||
#[diag("`objc::class!` may not contain null characters")]
|
||||
pub(crate) struct NullOnObjcClass {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_null_on_objc_selector)]
|
||||
#[diag("`objc::selector!` may not contain null characters")]
|
||||
pub(crate) struct NullOnObjcSelector {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_objc_class_expected_string_literal)]
|
||||
#[diag("`objc::class!` expected a string literal")]
|
||||
pub(crate) struct ObjcClassExpectedStringLiteral {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_objc_selector_expected_string_literal)]
|
||||
#[diag("`objc::selector!` expected a string literal")]
|
||||
pub(crate) struct ObjcSelectorExpectedStringLiteral {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_stability_outside_std, code = E0734)]
|
||||
#[diag("stability attributes may not be used outside of the standard library", code = E0734)]
|
||||
pub(crate) struct StabilityOutsideStd {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_empty_confusables)]
|
||||
#[diag("expected at least one confusable name")]
|
||||
pub(crate) struct EmptyConfusables {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[help]
|
||||
#[diag(attr_parsing_invalid_target)]
|
||||
#[help("`#[{$name}]` can {$only}be applied to {$applied}")]
|
||||
#[diag("`#[{$name}]` attribute cannot be used on {$target}")]
|
||||
pub(crate) struct InvalidTarget {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
|
||||
#[suggestion(
|
||||
"remove the attribute",
|
||||
code = "",
|
||||
applicability = "machine-applicable",
|
||||
style = "tool-only"
|
||||
)]
|
||||
pub span: Span,
|
||||
pub name: AttrPath,
|
||||
pub target: &'static str,
|
||||
|
|
@ -459,7 +475,7 @@ pub(crate) struct InvalidTarget {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_invalid_alignment_value, code = E0589)]
|
||||
#[diag("invalid alignment value: {$error_part}", code = E0589)]
|
||||
pub(crate) struct InvalidAlignmentValue {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -467,43 +483,49 @@ pub(crate) struct InvalidAlignmentValue {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_repr_ident, code = E0565)]
|
||||
#[diag("meta item in `repr` must be an identifier", code = E0565)]
|
||||
pub(crate) struct ReprIdent {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_unrecognized_repr_hint, code = E0552)]
|
||||
#[help]
|
||||
#[note]
|
||||
#[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>"
|
||||
)]
|
||||
pub(crate) struct UnrecognizedReprHint {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_unstable_feature_bound_incompatible_stability)]
|
||||
#[help]
|
||||
#[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]`"
|
||||
)]
|
||||
pub(crate) struct UnstableFeatureBoundIncompatibleStability {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_naked_functions_incompatible_attribute, code = E0736)]
|
||||
#[diag("attribute incompatible with `#[unsafe(naked)]`", code = E0736)]
|
||||
pub(crate) struct NakedFunctionIncompatibleAttribute {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
#[label("the `{$attr}` attribute is incompatible with `#[unsafe(naked)]`")]
|
||||
pub span: Span,
|
||||
#[label(attr_parsing_naked_attribute)]
|
||||
#[label("function marked with `#[unsafe(naked)]` here")]
|
||||
pub naked_span: Span,
|
||||
pub attr: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_link_ordinal_out_of_range)]
|
||||
#[note]
|
||||
#[diag("ordinal value in `link_ordinal` is too large: `{$ordinal}`")]
|
||||
#[note("the value may not exceed `u16::MAX`")]
|
||||
pub(crate) struct LinkOrdinalOutOfRange {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -511,19 +533,28 @@ pub(crate) struct LinkOrdinalOutOfRange {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_rustc_scalable_vector_count_out_of_range)]
|
||||
#[note]
|
||||
#[diag("element count in `rustc_scalable_vector` is too large: `{$n}`")]
|
||||
#[note("the value may not exceed `u16::MAX`")]
|
||||
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,
|
||||
|
|
@ -586,7 +617,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
|
|||
if let Some(start_point_span) = byte_string {
|
||||
diag.span_suggestion(
|
||||
start_point_span,
|
||||
fluent::attr_parsing_unsupported_literal_suggestion,
|
||||
"consider removing the prefix",
|
||||
"",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
|
@ -597,6 +628,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");
|
||||
}
|
||||
|
|
@ -751,30 +785,27 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_invalid_attr_unsafe)]
|
||||
#[note]
|
||||
#[diag("`{$name}` is not an unsafe attribute")]
|
||||
#[note("extraneous unsafe is not allowed in attributes")]
|
||||
pub(crate) struct InvalidAttrUnsafe {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
#[label("this is not an unsafe attribute")]
|
||||
pub span: Span,
|
||||
pub name: AttrPath,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_unsafe_attr_outside_unsafe)]
|
||||
#[diag("unsafe attribute used without unsafe")]
|
||||
pub(crate) struct UnsafeAttrOutsideUnsafe {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
#[label("usage of unsafe attribute")]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub suggestion: Option<UnsafeAttrOutsideUnsafeSuggestion>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
attr_parsing_unsafe_attr_outside_unsafe_suggestion,
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
#[multipart_suggestion("wrap the attribute in `unsafe(...)`", applicability = "machine-applicable")]
|
||||
pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion {
|
||||
#[suggestion_part(code = "unsafe(")]
|
||||
pub left: Span,
|
||||
|
|
@ -783,7 +814,7 @@ pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_meta_bad_delim)]
|
||||
#[diag("wrong meta list delimiters")]
|
||||
pub(crate) struct MetaBadDelim {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -793,7 +824,7 @@ pub(crate) struct MetaBadDelim {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
attr_parsing_meta_bad_delim_suggestion,
|
||||
"the delimiters should be `(` and `)`",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub(crate) struct MetaBadDelimSugg {
|
||||
|
|
@ -804,7 +835,7 @@ pub(crate) struct MetaBadDelimSugg {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_invalid_meta_item)]
|
||||
#[diag("expected a literal (`1u8`, `1.0f32`, `\"string\"`, etc.) here, found {$descr}")]
|
||||
pub(crate) struct InvalidMetaItem {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -813,12 +844,15 @@ pub(crate) struct InvalidMetaItem {
|
|||
pub quote_ident_sugg: Option<InvalidMetaItemQuoteIdentSugg>,
|
||||
#[subdiagnostic]
|
||||
pub remove_neg_sugg: Option<InvalidMetaItemRemoveNegSugg>,
|
||||
#[label]
|
||||
#[label("{$descr}s are not allowed here")]
|
||||
pub label: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(attr_parsing_quote_ident_sugg, applicability = "machine-applicable")]
|
||||
#[multipart_suggestion(
|
||||
"surround the identifier with quotation marks to make it into a string literal",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub(crate) struct InvalidMetaItemQuoteIdentSugg {
|
||||
#[suggestion_part(code = "\"")]
|
||||
pub before: Span,
|
||||
|
|
@ -827,73 +861,80 @@ pub(crate) struct InvalidMetaItemQuoteIdentSugg {
|
|||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(attr_parsing_remove_neg_sugg, applicability = "machine-applicable")]
|
||||
#[multipart_suggestion(
|
||||
"negative numbers are not literals, try removing the `-` sign",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub(crate) struct InvalidMetaItemRemoveNegSugg {
|
||||
#[suggestion_part(code = "")]
|
||||
pub negative_sign: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_suffixed_literal_in_attribute)]
|
||||
#[help]
|
||||
#[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.)"
|
||||
)]
|
||||
pub(crate) struct SuffixedLiteralInAttribute {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_empty_link_name, code = E0454)]
|
||||
#[diag("link name must not be empty", code = E0454)]
|
||||
pub(crate) struct EmptyLinkName {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
#[label("empty link name")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_link_framework_apple, code = E0455)]
|
||||
#[diag("link kind `framework` is only supported on Apple targets", code = E0455)]
|
||||
pub(crate) struct LinkFrameworkApple {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_incompatible_wasm_link)]
|
||||
#[diag("`wasm_import_module` is incompatible with other arguments in `#[link]` attributes")]
|
||||
pub(crate) struct IncompatibleWasmLink {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_link_requires_name, code = E0459)]
|
||||
#[diag("`#[link]` attribute requires a `name = \"string\"` argument", code = E0459)]
|
||||
pub(crate) struct LinkRequiresName {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
#[label("missing `name` argument")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_raw_dylib_no_nul)]
|
||||
#[diag("link name must not contain NUL characters if link kind is `raw-dylib`")]
|
||||
pub(crate) struct RawDylibNoNul {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_raw_dylib_only_windows, code = E0455)]
|
||||
#[diag("link kind `raw-dylib` is only supported on Windows targets", code = E0455)]
|
||||
pub(crate) struct RawDylibOnlyWindows {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_invalid_link_modifier)]
|
||||
#[diag(
|
||||
"invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed, export-symbols"
|
||||
)]
|
||||
pub(crate) struct InvalidLinkModifier {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_multiple_modifiers)]
|
||||
#[diag("multiple `{$modifier}` modifiers in a single `modifiers` argument")]
|
||||
pub(crate) struct MultipleModifiers {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -901,52 +942,61 @@ pub(crate) struct MultipleModifiers {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_import_name_type_x86)]
|
||||
#[diag("import name type is only supported on x86")]
|
||||
pub(crate) struct ImportNameTypeX86 {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_bundle_needs_static)]
|
||||
#[diag("linking modifier `bundle` is only compatible with `static` linking kind")]
|
||||
pub(crate) struct BundleNeedsStatic {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_whole_archive_needs_static)]
|
||||
#[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")]
|
||||
pub(crate) struct WholeArchiveNeedsStatic {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_as_needed_compatibility)]
|
||||
#[diag(
|
||||
"linking modifier `as-needed` is only compatible with `dylib`, `framework` and `raw-dylib` linking kinds"
|
||||
)]
|
||||
pub(crate) struct AsNeededCompatibility {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_import_name_type_raw)]
|
||||
#[diag("import name type can only be used with link kind `raw-dylib`")]
|
||||
pub(crate) struct ImportNameTypeRaw {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_limit_invalid)]
|
||||
#[diag("`limit` must be a non-negative integer")]
|
||||
pub(crate) struct LimitInvalid<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label]
|
||||
#[label("{$error_str}")]
|
||||
pub value_span: Span,
|
||||
pub error_str: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_cfg_attr_bad_delim)]
|
||||
#[diag("wrong `cfg_attr` delimiters")]
|
||||
pub(crate) struct CfgAttrBadDelim {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -955,14 +1005,25 @@ pub(crate) struct CfgAttrBadDelim {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_doc_alias_malformed)]
|
||||
#[diag(
|
||||
"doc alias attribute expects a string `#[doc(alias = \"a\")]` or a list of strings `#[doc(alias(\"a\", \"b\"))]`"
|
||||
)]
|
||||
pub(crate) struct DocAliasMalformed {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_unsupported_instruction_set)]
|
||||
#[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}::*)]`")]
|
||||
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];
|
||||
const ADT_LIKE: &[Target] = &[Target::Struct, Target::Enum, Target::Union];
|
||||
|
||||
let mut added_fake_targets = Vec::new();
|
||||
filter_targets(
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ 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" }
|
||||
|
|
|
|||
|
|
@ -1,296 +0,0 @@
|
|||
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
|
||||
|
|
@ -24,7 +24,6 @@ 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,
|
||||
};
|
||||
|
|
@ -49,11 +48,12 @@ 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: RegionElement<'tcx>,
|
||||
error_element: Option<ty::PlaceholderRegion<'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: RegionElement<'tcx>,
|
||||
error_element: Option<ty::PlaceholderRegion<'tcx>>,
|
||||
cause: ObligationCause<'tcx>,
|
||||
) {
|
||||
let tcx = mbcx.infcx.tcx;
|
||||
|
|
@ -169,22 +169,20 @@ pub(crate) trait TypeOpInfo<'tcx> {
|
|||
|
||||
let placeholder_region = ty::Region::new_placeholder(
|
||||
tcx,
|
||||
ty::Placeholder::new(adjusted_universe.into(), placeholder.bound),
|
||||
ty::PlaceholderRegion::new(adjusted_universe.into(), placeholder.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
|
||||
};
|
||||
// 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),
|
||||
)
|
||||
})
|
||||
});
|
||||
|
||||
debug!(?placeholder_region);
|
||||
|
||||
|
|
|
|||
|
|
@ -1256,7 +1256,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
self.suggest_cloning_inner(err, ty, expr);
|
||||
}
|
||||
} else if let ty::Adt(def, args) = ty.kind()
|
||||
&& def.did().as_local().is_some()
|
||||
&& let Some(local_did) = def.did().as_local()
|
||||
&& def.variants().iter().all(|variant| {
|
||||
variant
|
||||
.fields
|
||||
|
|
@ -1266,12 +1266,50 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
{
|
||||
let ty_span = self.infcx.tcx.def_span(def.did());
|
||||
let mut span: MultiSpan = ty_span.into();
|
||||
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,
|
||||
format!("if `{ty}` implemented `Clone`, you could clone the value"),
|
||||
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(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");
|
||||
}
|
||||
} 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())
|
||||
|
|
@ -2309,12 +2347,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
tcx: TyCtxt<'hir>,
|
||||
issue_span: Span,
|
||||
expr_span: Span,
|
||||
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>>,
|
||||
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,
|
||||
}
|
||||
impl<'hir> Visitor<'hir> for ExprFinder<'hir> {
|
||||
fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) {
|
||||
|
|
@ -2380,17 +2418,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
hir::intravisit::walk_expr(self, ex);
|
||||
}
|
||||
}
|
||||
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,
|
||||
};
|
||||
let mut finder = ExprFinder { tcx, expr_span: span, issue_span, .. };
|
||||
finder.visit_expr(tcx.hir_body(body_id).value);
|
||||
|
||||
if let Some(body_expr) = finder.body_expr
|
||||
|
|
@ -2625,13 +2653,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
|
||||
struct ExpressionFinder<'tcx> {
|
||||
capture_span: Span,
|
||||
closure_change_spans: Vec<Span>,
|
||||
closure_arg_span: Option<Span>,
|
||||
in_closure: bool,
|
||||
suggest_arg: String,
|
||||
closure_change_spans: Vec<Span> = vec![],
|
||||
closure_arg_span: Option<Span> = None,
|
||||
in_closure: bool = false,
|
||||
suggest_arg: String = String::new(),
|
||||
tcx: TyCtxt<'tcx>,
|
||||
closure_local_id: Option<hir::HirId>,
|
||||
closure_call_changes: Vec<(Span, String)>,
|
||||
closure_local_id: Option<hir::HirId> = None,
|
||||
closure_call_changes: Vec<(Span, String)> = vec![],
|
||||
}
|
||||
impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> {
|
||||
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
|
||||
|
|
@ -2712,16 +2740,8 @@ 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,
|
||||
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,
|
||||
};
|
||||
let mut finder =
|
||||
ExpressionFinder { capture_span: *capture_kind_span, tcx: self.infcx.tcx, .. };
|
||||
finder.visit_expr(expr);
|
||||
|
||||
if finder.closure_change_spans.is_empty() || finder.closure_call_changes.is_empty() {
|
||||
|
|
|
|||
|
|
@ -649,8 +649,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_diagnostics) = self.polonius_diagnostics {
|
||||
polonius_diagnostics.boring_nll_locals.contains(&local)
|
||||
if let Some(polonius_context) = self.polonius_context {
|
||||
polonius_context.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, EmissionGuarantee, MultiSpan, listify};
|
||||
use rustc_errors::{Applicability, Diag, DiagMessage, EmissionGuarantee, MultiSpan, listify, msg};
|
||||
use rustc_hir::def::{CtorKind, Namespace};
|
||||
use rustc_hir::{
|
||||
self as hir, CoroutineKind, GenericBound, LangItem, WhereBoundPredicate, WherePredicateKind,
|
||||
|
|
@ -35,7 +35,6 @@ 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,
|
||||
|
|
@ -700,7 +699,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, fluent::borrowck_limitations_implies_static);
|
||||
diag.span_note(pred.span, LIMITATION_NOTE);
|
||||
return;
|
||||
}
|
||||
for bound in bounds.iter() {
|
||||
|
|
@ -711,7 +710,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, fluent::borrowck_limitations_implies_static);
|
||||
diag.span_note(bound.span, LIMITATION_NOTE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -1312,7 +1311,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(
|
||||
fluent::borrowck_moved_a_fn_once_in_call_def,
|
||||
msg!("`{$ty}` is made to be an `FnOnce` closure here"),
|
||||
err.args.iter(),
|
||||
);
|
||||
err.remove_arg("ty");
|
||||
|
|
@ -1321,9 +1320,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
}
|
||||
span.push_span_label(
|
||||
fn_call_span,
|
||||
fluent::borrowck_moved_a_fn_once_in_call,
|
||||
msg!("this value implements `FnOnce`, which causes it to be moved when called"),
|
||||
);
|
||||
err.span_note(span, fluent::borrowck_moved_a_fn_once_in_call_call);
|
||||
err.span_note(span, msg!("`FnOnce` closures can only be called once"));
|
||||
} else {
|
||||
err.subdiagnostic(CaptureReasonNote::FnOnceMoveInCall { var_span });
|
||||
}
|
||||
|
|
@ -1568,3 +1567,6 @@ 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,3 +1,4 @@
|
|||
use rustc_abi::FieldIdx;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{Applicability, Diag};
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
|
|
@ -7,7 +8,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, DUMMY_SP, ExpnKind, MacroKind, Span};
|
||||
use rustc_span::{BytePos, ExpnKind, MacroKind, Span};
|
||||
use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use tracing::debug;
|
||||
|
|
@ -472,49 +473,30 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
if def_id.as_local() == Some(self.mir_def_id())
|
||||
&& let Some(upvar_field) = upvar_field =>
|
||||
{
|
||||
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",
|
||||
)
|
||||
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 source = self.borrowed_content_source(deref_base);
|
||||
|
|
@ -563,45 +545,134 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
err
|
||||
}
|
||||
|
||||
fn get_closure_bound_clause_span(&self, def_id: DefId) -> Span {
|
||||
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> {
|
||||
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 DUMMY_SP };
|
||||
let hir::Node::Expr(parent) = tcx.parent_hir_node(closure_hir_id) else { return None };
|
||||
|
||||
let predicates = match parent.kind {
|
||||
hir::ExprKind::Call(callee, _) => {
|
||||
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 };
|
||||
let ty = typeck_result.node_type_opt(callee.hir_id)?;
|
||||
let ty::FnDef(fn_def_id, args) = ty.kind() else { return None };
|
||||
tcx.predicates_of(fn_def_id).instantiate(tcx, args)
|
||||
}
|
||||
hir::ExprKind::MethodCall(..) => {
|
||||
let Some((_, method)) = typeck_result.type_dependent_def(parent.hir_id) else {
|
||||
return DUMMY_SP;
|
||||
};
|
||||
let (_, method) = typeck_result.type_dependent_def(parent.hir_id)?;
|
||||
let args = typeck_result.node_args(parent.hir_id);
|
||||
tcx.predicates_of(method).instantiate(tcx, args)
|
||||
}
|
||||
_ => return DUMMY_SP,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
// Check whether one of the where-bounds requires the closure to impl `Fn[Mut]`.
|
||||
// Check whether one of the where-bounds requires the closure to impl `Fn[Mut]`
|
||||
// or `AsyncFn[Mut]`.
|
||||
for (pred, span) in predicates.predicates.iter().zip(predicates.spans.iter()) {
|
||||
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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
DUMMY_SP
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span: Span) {
|
||||
|
|
|
|||
|
|
@ -354,14 +354,71 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
self.infcx.tcx.sess.source_map().span_to_snippet(source_info.span)
|
||||
{
|
||||
if snippet.starts_with("&mut ") {
|
||||
// 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,
|
||||
);
|
||||
// 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,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// This can occur with things like `(&mut self).foo()`.
|
||||
err.span_help(source_info.span, "try removing `&mut` here");
|
||||
|
|
@ -1695,7 +1752,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)
|
||||
&& let Ok(rhs_str_new) = tcx.sess.source_map().span_to_snippet(rhs_span_new)
|
||||
{
|
||||
(rvalue, rhs_span, rhs_str) = (rvalue_new, rhs_span_new, rhs_str_new);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//! Error reporting machinery for lifetime errors.
|
||||
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan};
|
||||
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, msg};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::GenericBound::Trait;
|
||||
use rustc_hir::QPath::Resolved;
|
||||
|
|
@ -27,16 +27,15 @@ use rustc_trait_selection::infer::InferCtxtExt;
|
|||
use rustc_trait_selection::traits::{Obligation, ObligationCtxt};
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
use super::{OutlivesSuggestionBuilder, RegionName, RegionNameSource};
|
||||
use super::{LIMITATION_NOTE, 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, fluent_generated as fluent};
|
||||
use crate::{MirBorrowckCtxt, borrowck_errors};
|
||||
|
||||
impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> {
|
||||
fn description(&self) -> &'static str {
|
||||
|
|
@ -104,15 +103,9 @@ pub(crate) enum RegionErrorKind<'tcx> {
|
|||
/// A generic bound failure for a type test (`T: 'a`).
|
||||
TypeTestError { type_test: TypeTest<'tcx> },
|
||||
|
||||
/// 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>,
|
||||
},
|
||||
/// '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 },
|
||||
|
||||
/// Any other lifetime error.
|
||||
RegionError {
|
||||
|
|
@ -265,7 +258,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
let Trait(PolyTraitRef { trait_ref, span: trait_span, .. }) = bound else {
|
||||
return;
|
||||
};
|
||||
diag.span_note(*trait_span, fluent::borrowck_limitations_implies_static);
|
||||
diag.span_note(*trait_span, LIMITATION_NOTE);
|
||||
let Some(generics_fn) = tcx.hir_get_generics(self.body.source.def_id().expect_local())
|
||||
else {
|
||||
return;
|
||||
|
|
@ -298,7 +291,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
if suggestions.len() > 0 {
|
||||
suggestions.dedup();
|
||||
diag.multipart_suggestion_verbose(
|
||||
fluent::borrowck_restrict_to_static,
|
||||
msg!("consider restricting the type parameter to the `'static` lifetime"),
|
||||
suggestions,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
|
@ -360,28 +353,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
RegionErrorKind::BoundUniversalRegionError {
|
||||
RegionErrorKind::PlaceholderOutlivesIllegalRegion {
|
||||
longer_fr,
|
||||
placeholder,
|
||||
error_element,
|
||||
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);
|
||||
self.report_erroneous_rvid_reaches_placeholder(longer_fr, illegally_outlived_r)
|
||||
}
|
||||
|
||||
RegionErrorKind::RegionError { fr_origin, longer_fr, shorter_fr, is_reported } => {
|
||||
|
|
@ -412,6 +388,43 @@ 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:
|
||||
///
|
||||
|
|
@ -872,6 +885,7 @@ 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 {
|
||||
|
|
@ -966,12 +980,18 @@ 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, fluent::borrowck_implicit_static);
|
||||
multi_span.push_span_label(ident.span, fluent::borrowck_implicit_static_introduced);
|
||||
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"),
|
||||
);
|
||||
err.subdiagnostic(RequireStaticErr::UsedImpl { multi_span });
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_hi(),
|
||||
fluent::borrowck_implicit_static_relax,
|
||||
msg!("consider relaxing the implicit `'static` requirement"),
|
||||
" + '_",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
|
@ -1134,7 +1154,7 @@ 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(),
|
||||
fluent::borrowck_dereference_suggestion,
|
||||
msg!("dereference the return value"),
|
||||
"*".repeat(count),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
|
|
@ -1178,7 +1198,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
if let Some(closure_span) = closure_span {
|
||||
diag.span_suggestion_verbose(
|
||||
closure_span,
|
||||
fluent::borrowck_move_closure_suggestion,
|
||||
msg!("consider adding 'move' keyword before the nested closure"),
|
||||
"move ",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@
|
|||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![feature(assert_matches)]
|
||||
#![cfg_attr(bootstrap, feature(assert_matches))]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(default_field_values)]
|
||||
#![feature(file_buffered)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(negative_impls)]
|
||||
|
|
@ -62,10 +63,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;
|
||||
|
|
@ -98,8 +99,6 @@ 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 ()>);
|
||||
|
||||
|
|
@ -122,6 +121,11 @@ 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");
|
||||
|
|
@ -420,7 +424,7 @@ fn borrowck_check_region_constraints<'tcx>(
|
|||
polonius_output,
|
||||
opt_closure_req,
|
||||
nll_errors,
|
||||
polonius_diagnostics,
|
||||
polonius_context,
|
||||
} = nll::compute_regions(
|
||||
root_cx,
|
||||
&infcx,
|
||||
|
|
@ -444,7 +448,7 @@ fn borrowck_check_region_constraints<'tcx>(
|
|||
®ioncx,
|
||||
&opt_closure_req,
|
||||
&borrow_set,
|
||||
polonius_diagnostics.as_ref(),
|
||||
polonius_context.as_ref(),
|
||||
);
|
||||
|
||||
// We also have a `#[rustc_regions]` annotation that causes us to dump
|
||||
|
|
@ -486,7 +490,7 @@ fn borrowck_check_region_constraints<'tcx>(
|
|||
polonius_output: None,
|
||||
move_errors: Vec::new(),
|
||||
diags_buffer,
|
||||
polonius_diagnostics: polonius_diagnostics.as_ref(),
|
||||
polonius_context: polonius_context.as_ref(),
|
||||
};
|
||||
struct MoveVisitor<'a, 'b, 'infcx, 'tcx> {
|
||||
ctxt: &'a mut MirBorrowckCtxt<'b, 'infcx, 'tcx>,
|
||||
|
|
@ -525,7 +529,7 @@ fn borrowck_check_region_constraints<'tcx>(
|
|||
move_errors: Vec::new(),
|
||||
diags_buffer,
|
||||
polonius_output: polonius_output.as_deref(),
|
||||
polonius_diagnostics: polonius_diagnostics.as_ref(),
|
||||
polonius_context: polonius_context.as_ref(),
|
||||
};
|
||||
|
||||
// Compute and report region errors, if any.
|
||||
|
|
@ -775,7 +779,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_diagnostics: Option<&'a PoloniusDiagnosticsContext>,
|
||||
polonius_context: Option<&'a PoloniusContext>,
|
||||
}
|
||||
|
||||
// Check that:
|
||||
|
|
@ -1206,6 +1210,17 @@ 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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ 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};
|
||||
|
|
@ -15,17 +17,16 @@ 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;
|
||||
|
|
@ -46,7 +47,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_diagnostics: Option<PoloniusDiagnosticsContext>,
|
||||
pub polonius_context: Option<PoloniusContext>,
|
||||
}
|
||||
|
||||
/// Rewrites the regions in the MIR to use NLL variables, also scraping out the set of universal
|
||||
|
|
@ -121,7 +122,7 @@ pub(crate) fn compute_regions<'tcx>(
|
|||
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
|
||||
constraints: MirTypeckRegionConstraints<'tcx>,
|
||||
mut polonius_facts: Option<AllFacts<RustcFacts>>,
|
||||
polonius_context: Option<PoloniusContext>,
|
||||
mut 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();
|
||||
|
|
@ -153,9 +154,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.
|
||||
let polonius_diagnostics = polonius_context.map(|polonius_context| {
|
||||
polonius_context.compute_loan_liveness(infcx.tcx, &mut regioncx, body, borrow_set)
|
||||
});
|
||||
if let Some(polonius_context) = polonius_context.as_mut() {
|
||||
polonius_context.compute_loan_liveness(&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| {
|
||||
|
|
@ -188,7 +189,7 @@ pub(crate) fn compute_regions<'tcx>(
|
|||
polonius_output,
|
||||
opt_closure_req: closure_region_requirements,
|
||||
nll_errors,
|
||||
polonius_diagnostics,
|
||||
polonius_context,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -230,13 +231,13 @@ pub(super) fn dump_nll_mir<'tcx>(
|
|||
dumper.dump_mir(body);
|
||||
|
||||
// Also dump the region constraint graph as a graphviz file.
|
||||
let _: io::Result<()> = try {
|
||||
let _ = 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 _: io::Result<()> = try {
|
||||
let _ = try {
|
||||
let mut file = dumper.create_dump_file("regioncx.scc.dot", body)?;
|
||||
regioncx.dump_graphviz_scc_constraints(tcx, &mut file)?;
|
||||
};
|
||||
|
|
@ -295,7 +296,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 !tcx.has_attr(base_def_id, sym::rustc_regions) {
|
||||
if !find_attr!(tcx.get_all_attrs(base_def_id), AttributeKind::RustcRegions) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,19 @@
|
|||
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.
|
||||
|
|
@ -12,32 +25,300 @@ use rustc_mir_dataflow::points::PointIndex;
|
|||
/// 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.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub(crate) struct LocalizedOutlivesConstraint {
|
||||
pub source: RegionVid,
|
||||
pub from: PointIndex,
|
||||
pub target: RegionVid,
|
||||
pub to: PointIndex,
|
||||
///
|
||||
/// 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,
|
||||
}
|
||||
|
||||
/// 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 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>>,
|
||||
}
|
||||
|
||||
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);
|
||||
/// 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 })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,9 +10,7 @@ use rustc_session::config::MirIncludeSpans;
|
|||
|
||||
use crate::borrow_set::BorrowSet;
|
||||
use crate::constraints::OutlivesConstraint;
|
||||
use crate::polonius::{
|
||||
LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet, PoloniusDiagnosticsContext,
|
||||
};
|
||||
use crate::polonius::{LocalizedConstraintGraphVisitor, LocalizedNode, PoloniusContext};
|
||||
use crate::region_infer::values::LivenessValues;
|
||||
use crate::type_check::Locations;
|
||||
use crate::{BorrowckInferCtxt, ClosureRegionRequirements, RegionInferenceContext};
|
||||
|
|
@ -24,7 +22,7 @@ pub(crate) fn dump_polonius_mir<'tcx>(
|
|||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
polonius_diagnostics: Option<&PoloniusDiagnosticsContext>,
|
||||
polonius_context: Option<&PoloniusContext>,
|
||||
) {
|
||||
let tcx = infcx.tcx;
|
||||
if !tcx.sess.opts.unstable_opts.polonius.is_next_enabled() {
|
||||
|
|
@ -33,8 +31,22 @@ pub(crate) fn dump_polonius_mir<'tcx>(
|
|||
|
||||
let Some(dumper) = MirDumper::new(tcx, "polonius", body) else { return };
|
||||
|
||||
let polonius_diagnostics =
|
||||
polonius_diagnostics.expect("missing diagnostics context with `-Zpolonius=next`");
|
||||
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 extra_data = &|pass_where, out: &mut dyn io::Write| {
|
||||
emit_polonius_mir(
|
||||
|
|
@ -42,7 +54,7 @@ pub(crate) fn dump_polonius_mir<'tcx>(
|
|||
regioncx,
|
||||
closure_region_requirements,
|
||||
borrow_set,
|
||||
&polonius_diagnostics.localized_outlives_constraints,
|
||||
&collector.constraints,
|
||||
pass_where,
|
||||
out,
|
||||
)
|
||||
|
|
@ -58,19 +70,36 @@ pub(crate) fn dump_polonius_mir<'tcx>(
|
|||
|
||||
let dumper = dumper.set_extra_data(extra_data).set_options(options);
|
||||
|
||||
let _: io::Result<()> = try {
|
||||
let _ = try {
|
||||
let mut file = dumper.create_dump_file("html", body)?;
|
||||
emit_polonius_dump(
|
||||
&dumper,
|
||||
body,
|
||||
regioncx,
|
||||
borrow_set,
|
||||
&polonius_diagnostics.localized_outlives_constraints,
|
||||
&mut file,
|
||||
)?;
|
||||
emit_polonius_dump(&dumper, body, regioncx, borrow_set, &collector.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
|
||||
|
|
@ -82,7 +111,7 @@ fn emit_polonius_dump<'tcx>(
|
|||
body: &Body<'tcx>,
|
||||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
localized_outlives_constraints: &LocalizedOutlivesConstraintSet,
|
||||
localized_outlives_constraints: &[LocalizedOutlivesConstraint],
|
||||
out: &mut dyn io::Write,
|
||||
) -> io::Result<()> {
|
||||
// Prepare the HTML dump file prologue.
|
||||
|
|
@ -193,7 +222,7 @@ fn emit_polonius_mir<'tcx>(
|
|||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
localized_outlives_constraints: &LocalizedOutlivesConstraintSet,
|
||||
localized_outlives_constraints: &[LocalizedOutlivesConstraint],
|
||||
pass_where: PassWhere,
|
||||
out: &mut dyn io::Write,
|
||||
) -> io::Result<()> {
|
||||
|
|
@ -212,10 +241,10 @@ fn emit_polonius_mir<'tcx>(
|
|||
// Add localized outlives constraints
|
||||
match pass_where {
|
||||
PassWhere::BeforeCFG => {
|
||||
if localized_outlives_constraints.outlives.len() > 0 {
|
||||
if localized_outlives_constraints.len() > 0 {
|
||||
writeln!(out, "| Localized constraints")?;
|
||||
|
||||
for constraint in &localized_outlives_constraints.outlives {
|
||||
for constraint in localized_outlives_constraints {
|
||||
let LocalizedOutlivesConstraint { source, from, target, to } = constraint;
|
||||
let from = liveness.location_from_point(*from);
|
||||
let to = liveness.location_from_point(*to);
|
||||
|
|
@ -399,7 +428,7 @@ fn emit_mermaid_nll_sccs<'tcx>(
|
|||
fn emit_mermaid_constraint_graph<'tcx>(
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
liveness: &LivenessValues,
|
||||
localized_outlives_constraints: &LocalizedOutlivesConstraintSet,
|
||||
localized_outlives_constraints: &[LocalizedOutlivesConstraint],
|
||||
out: &mut dyn io::Write,
|
||||
) -> io::Result<usize> {
|
||||
let location_name = |location: Location| {
|
||||
|
|
@ -438,7 +467,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.outlives {
|
||||
for constraint in localized_outlives_constraints {
|
||||
points_per_region.entry(constraint.source).or_default().insert(constraint.from);
|
||||
points_per_region.entry(constraint.target).or_default().insert(constraint.to);
|
||||
}
|
||||
|
|
@ -451,7 +480,7 @@ fn emit_mermaid_constraint_graph<'tcx>(
|
|||
}
|
||||
|
||||
// The constraint graph edges.
|
||||
for constraint in &localized_outlives_constraints.outlives {
|
||||
for constraint in localized_outlives_constraints {
|
||||
// FIXME: add killed loans and constraint kind as edge labels.
|
||||
writeln!(
|
||||
out,
|
||||
|
|
@ -463,6 +492,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.outlives.len();
|
||||
let edge_count = borrow_set.len() + localized_outlives_constraints.len();
|
||||
Ok(edge_count)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +1,15 @@
|
|||
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, LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet,
|
||||
PoloniusLivenessContext,
|
||||
};
|
||||
use crate::region_infer::values::LivenessValues;
|
||||
use super::{ConstraintDirection, PoloniusContext};
|
||||
use crate::universal_regions::UniversalRegions;
|
||||
|
||||
impl PoloniusLivenessContext {
|
||||
impl PoloniusContext {
|
||||
/// Record the variance of each region contained within the given value.
|
||||
pub(crate) fn record_live_region_variance<'tcx>(
|
||||
&mut self,
|
||||
|
|
@ -34,165 +27,6 @@ impl PoloniusLivenessContext {
|
|||
}
|
||||
}
|
||||
|
||||
/// 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.
|
||||
|
|
|
|||
|
|
@ -1,160 +0,0 @@
|
|||
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,47 +32,37 @@
|
|||
//! - <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, TyCtxt};
|
||||
use rustc_middle::ty::RegionVid;
|
||||
use rustc_mir_dataflow::points::PointIndex;
|
||||
|
||||
pub(crate) use self::constraints::*;
|
||||
pub(self) 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 liveness data created during MIR typeck, and which will be used later in
|
||||
/// the process, to compute the polonius localized constraints.
|
||||
/// 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.
|
||||
#[derive(Default)]
|
||||
pub(crate) struct PoloniusLivenessContext {
|
||||
pub(crate) struct PoloniusContext {
|
||||
/// The graph from which we extract the localized outlives constraints.
|
||||
graph: Option<LocalizedConstraintGraph>,
|
||||
|
||||
/// The expected edge direction per live region: the kind of directed edge we'll create as
|
||||
/// liveness constraints depends on the variance of types with respect to each contained region.
|
||||
live_region_variances: BTreeMap<RegionVid, ConstraintDirection>,
|
||||
|
|
@ -84,27 +74,6 @@ pub(crate) struct PoloniusLivenessContext {
|
|||
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)]
|
||||
|
|
@ -120,26 +89,6 @@ 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:
|
||||
|
|
@ -151,44 +100,90 @@ impl PoloniusContext {
|
|||
///
|
||||
/// The constraint data will be used to compute errors and diagnostics.
|
||||
pub(crate) fn compute_loan_liveness<'tcx>(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
&mut self,
|
||||
regioncx: &mut RegionInferenceContext<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
) -> PoloniusDiagnosticsContext {
|
||||
let PoloniusLivenessContext { live_region_variances, boring_nll_locals } =
|
||||
self.liveness_context;
|
||||
) {
|
||||
let liveness = regioncx.liveness_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,
|
||||
);
|
||||
// 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());
|
||||
|
||||
create_liveness_constraints(
|
||||
body,
|
||||
regioncx.liveness_constraints(),
|
||||
&self.live_regions,
|
||||
&live_region_variances,
|
||||
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);
|
||||
|
||||
// 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 }
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,208 +0,0 @@
|
|||
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,
|
||||
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>,
|
||||
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"
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
// Assignments should be the only statement that can both generate constraints that
|
||||
// apply on entry (specific to the RHS place) *and* others that only apply on exit (the
|
||||
// subset of RHS regions that actually flow into the LHS): i.e., where midpoints would
|
||||
// be used to ensure the former happen before the latter, within the same MIR Location.
|
||||
}
|
||||
}
|
||||
|
||||
// We generally localize an outlives constraint to where it arises.
|
||||
LocalizedOutlivesConstraint {
|
||||
source: outlives_constraint.sup,
|
||||
from: current_point,
|
||||
target: outlives_constraint.sub,
|
||||
to: current_point,
|
||||
}
|
||||
}
|
||||
|
||||
/// For a given outlives constraint arising from a MIR terminator, localize the constraint with the
|
||||
/// 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.
|
||||
match &terminator.kind {
|
||||
// FIXME: also handle diverging calls.
|
||||
TerminatorKind::Call { destination, target: Some(target), .. } => {
|
||||
// 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::NamedAnon(_) => {
|
||||
ty::BoundRegionKind::NamedForPrinting(_) => {
|
||||
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::BoundUniversalRegionError {
|
||||
errors_buffer.push(RegionErrorKind::PlaceholderOutlivesIllegalRegion {
|
||||
longer_fr,
|
||||
error_element,
|
||||
placeholder,
|
||||
illegally_outlived_r,
|
||||
});
|
||||
} 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`.
|
||||
pub(crate) fn region_from_element(
|
||||
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,6 +126,31 @@ 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.
|
||||
|
|
@ -176,11 +201,13 @@ 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();
|
||||
|
|
@ -204,8 +231,10 @@ 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,
|
||||
);
|
||||
|
|
@ -274,8 +303,10 @@ 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>>,
|
||||
) {
|
||||
|
|
@ -293,16 +324,29 @@ fn compute_definition_site_hidden_types_from_defining_uses<'tcx>(
|
|||
Ok(hidden_type) => hidden_type,
|
||||
Err(r) => {
|
||||
debug!("UnexpectedHiddenRegion: {:?}", r);
|
||||
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)
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -570,6 +614,40 @@ 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,9 +131,17 @@ impl LivenessValues {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns whether `region` is marked live at the given `location`.
|
||||
/// Returns whether `region` is marked live at the given
|
||||
/// [`location`][rustc_middle::mir::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 {
|
||||
|
|
@ -420,18 +428,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::Placeholder<TyCtxt<'tcx>, ty::BoundRegion>>,
|
||||
Self: Into<ty::PlaceholderRegion<'tcx>>,
|
||||
{
|
||||
let placeholder: ty::Placeholder<TyCtxt<'tcx>, ty::BoundRegion> = self.into();
|
||||
let placeholder: ty::PlaceholderRegion<'tcx> = 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::Placeholder<TyCtxt<'tcx>, ty::BoundRegion>>,
|
||||
Self: Into<ty::PlaceholderRegion<'tcx>>,
|
||||
{
|
||||
let placeholder: ty::Placeholder<TyCtxt<'tcx>, ty::BoundRegion> = self.into();
|
||||
let placeholder: ty::PlaceholderRegion<'tcx> = self.into();
|
||||
let index = values.placeholder_indices.lookup_index(placeholder);
|
||||
values.placeholders.contains(row, index)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,9 @@ use smallvec::SmallVec;
|
|||
use crate::consumers::BorrowckConsumer;
|
||||
use crate::nll::compute_closure_requirements_modulo_opaques;
|
||||
use crate::region_infer::opaque_types::{
|
||||
apply_definition_site_hidden_types, clone_and_resolve_opaque_types,
|
||||
UnexpectedHiddenRegion, 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::{
|
||||
|
|
@ -26,7 +27,12 @@ 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.
|
||||
|
|
@ -49,6 +55,7 @@ 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,
|
||||
|
|
@ -84,23 +91,32 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> {
|
|||
|
||||
fn handle_opaque_type_uses(&mut self) {
|
||||
let mut per_body_info = Vec::new();
|
||||
for input in self.collect_region_constraints_results.values_mut() {
|
||||
for (def_id, input) in &mut self.collect_region_constraints_results {
|
||||
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(borrowck_move_unsized, code = E0161)]
|
||||
#[diag("cannot move a value of type `{$ty}`", code = E0161)]
|
||||
pub(crate) struct MoveUnsized<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
#[primary_span]
|
||||
#[label]
|
||||
#[label("the size of `{$ty}` cannot be statically determined")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(borrowck_higher_ranked_lifetime_error)]
|
||||
#[diag("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(borrowck_could_not_prove)]
|
||||
#[note("could not prove `{$predicate}`")]
|
||||
CouldNotProve { predicate: String },
|
||||
#[note(borrowck_could_not_normalize)]
|
||||
#[note("could not normalize `{$value}`")]
|
||||
CouldNotNormalize { value: String },
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(borrowck_higher_ranked_subtype_error)]
|
||||
#[diag("higher-ranked subtype error")]
|
||||
pub(crate) struct HigherRankedSubtypeError {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(borrowck_generic_does_not_live_long_enough)]
|
||||
#[diag("`{$kind}` does not live long enough")]
|
||||
pub(crate) struct GenericDoesNotLiveLongEnough {
|
||||
pub kind: String,
|
||||
#[primary_span]
|
||||
|
|
@ -48,15 +48,20 @@ pub(crate) struct GenericDoesNotLiveLongEnough {
|
|||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(borrowck_var_does_not_need_mut)]
|
||||
#[diag("variable does not need to be mutable")]
|
||||
pub(crate) struct VarNeedNotMut {
|
||||
#[suggestion(style = "short", applicability = "machine-applicable", code = "")]
|
||||
#[suggestion(
|
||||
"remove this `mut`",
|
||||
style = "short",
|
||||
applicability = "machine-applicable",
|
||||
code = ""
|
||||
)]
|
||||
pub span: Span,
|
||||
}
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(borrowck_var_cannot_escape_closure)]
|
||||
#[note]
|
||||
#[note(borrowck_cannot_escape)]
|
||||
#[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")]
|
||||
pub(crate) struct FnMutError {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -66,17 +71,17 @@ pub(crate) struct FnMutError {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum VarHereDenote {
|
||||
#[label(borrowck_var_here_captured)]
|
||||
#[label("variable captured here")]
|
||||
Captured {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[label(borrowck_var_here_defined)]
|
||||
#[label("variable defined here")]
|
||||
Defined {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[label(borrowck_closure_inferred_mut)]
|
||||
#[label("inferred to be a `FnMut` closure")]
|
||||
FnMutInferred {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
|
|
@ -85,17 +90,21 @@ pub(crate) enum VarHereDenote {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum FnMutReturnTypeErr {
|
||||
#[label(borrowck_returned_closure_escaped)]
|
||||
#[label(
|
||||
"returns a closure that contains a reference to a captured variable, which then escapes the closure body"
|
||||
)]
|
||||
ReturnClosure {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[label(borrowck_returned_async_block_escaped)]
|
||||
#[label(
|
||||
"returns an `async` block that contains a reference to a captured variable, which then escapes the closure body"
|
||||
)]
|
||||
ReturnAsyncBlock {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[label(borrowck_returned_ref_escaped)]
|
||||
#[label("returns a reference to a captured variable which escapes the closure body")]
|
||||
ReturnRef {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
|
|
@ -103,7 +112,7 @@ pub(crate) enum FnMutReturnTypeErr {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(borrowck_lifetime_constraints_error)]
|
||||
#[diag("lifetime may not live long enough")]
|
||||
pub(crate) struct LifetimeOutliveErr {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -111,7 +120,9 @@ pub(crate) struct LifetimeOutliveErr {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum LifetimeReturnCategoryErr<'a> {
|
||||
#[label(borrowck_returned_lifetime_wrong)]
|
||||
#[label(
|
||||
"{$mir_def_name} was supposed to return data with lifetime `{$outlived_fr_name}` but it is returning data with lifetime `{$fr_name}`"
|
||||
)]
|
||||
WrongReturn {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
|
|
@ -119,7 +130,9 @@ pub(crate) enum LifetimeReturnCategoryErr<'a> {
|
|||
outlived_fr_name: RegionName,
|
||||
fr_name: &'a RegionName,
|
||||
},
|
||||
#[label(borrowck_returned_lifetime_short)]
|
||||
#[label(
|
||||
"{$category_desc}requires that `{$free_region_name}` must outlive `{$outlived_fr_name}`"
|
||||
)]
|
||||
ShortReturn {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
|
|
@ -131,7 +144,7 @@ pub(crate) enum LifetimeReturnCategoryErr<'a> {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum RequireStaticErr {
|
||||
#[note(borrowck_used_impl_require_static)]
|
||||
#[note("the used `impl` has a `'static` requirement")]
|
||||
UsedImpl {
|
||||
#[primary_span]
|
||||
multi_span: MultiSpan,
|
||||
|
|
@ -140,42 +153,42 @@ pub(crate) enum RequireStaticErr {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum CaptureVarPathUseCause {
|
||||
#[label(borrowck_borrow_due_to_use_coroutine)]
|
||||
#[label("borrow occurs due to use in coroutine")]
|
||||
BorrowInCoroutine {
|
||||
#[primary_span]
|
||||
path_span: Span,
|
||||
},
|
||||
#[label(borrowck_use_due_to_use_coroutine)]
|
||||
#[label("use occurs due to use in coroutine")]
|
||||
UseInCoroutine {
|
||||
#[primary_span]
|
||||
path_span: Span,
|
||||
},
|
||||
#[label(borrowck_assign_due_to_use_coroutine)]
|
||||
#[label("assign occurs due to use in coroutine")]
|
||||
AssignInCoroutine {
|
||||
#[primary_span]
|
||||
path_span: Span,
|
||||
},
|
||||
#[label(borrowck_assign_part_due_to_use_coroutine)]
|
||||
#[label("assign to part occurs due to use in coroutine")]
|
||||
AssignPartInCoroutine {
|
||||
#[primary_span]
|
||||
path_span: Span,
|
||||
},
|
||||
#[label(borrowck_borrow_due_to_use_closure)]
|
||||
#[label("borrow occurs due to use in closure")]
|
||||
BorrowInClosure {
|
||||
#[primary_span]
|
||||
path_span: Span,
|
||||
},
|
||||
#[label(borrowck_use_due_to_use_closure)]
|
||||
#[label("use occurs due to use in closure")]
|
||||
UseInClosure {
|
||||
#[primary_span]
|
||||
path_span: Span,
|
||||
},
|
||||
#[label(borrowck_assign_due_to_use_closure)]
|
||||
#[label("assignment occurs due to use in closure")]
|
||||
AssignInClosure {
|
||||
#[primary_span]
|
||||
path_span: Span,
|
||||
},
|
||||
#[label(borrowck_assign_part_due_to_use_closure)]
|
||||
#[label("assignment to part occurs due to use in closure")]
|
||||
AssignPartInClosure {
|
||||
#[primary_span]
|
||||
path_span: Span,
|
||||
|
|
@ -184,17 +197,17 @@ pub(crate) enum CaptureVarPathUseCause {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum CaptureVarKind {
|
||||
#[label(borrowck_capture_immute)]
|
||||
#[label("capture is immutable because of use here")]
|
||||
Immut {
|
||||
#[primary_span]
|
||||
kind_span: Span,
|
||||
},
|
||||
#[label(borrowck_capture_mut)]
|
||||
#[label("capture is mutable because of use here")]
|
||||
Mut {
|
||||
#[primary_span]
|
||||
kind_span: Span,
|
||||
},
|
||||
#[label(borrowck_capture_move)]
|
||||
#[label("capture is moved because of use here")]
|
||||
Move {
|
||||
#[primary_span]
|
||||
kind_span: Span,
|
||||
|
|
@ -203,77 +216,97 @@ pub(crate) enum CaptureVarKind {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum CaptureVarCause {
|
||||
#[label(borrowck_var_borrow_by_use_place_in_coroutine)]
|
||||
#[label(
|
||||
"{$is_single_var ->
|
||||
*[true] borrow occurs
|
||||
[false] borrows occur
|
||||
} due to use of {$place} in coroutine"
|
||||
)]
|
||||
BorrowUsePlaceCoroutine {
|
||||
is_single_var: bool,
|
||||
place: String,
|
||||
#[primary_span]
|
||||
var_span: Span,
|
||||
},
|
||||
#[label(borrowck_var_borrow_by_use_place_in_closure)]
|
||||
#[label(
|
||||
"{$is_single_var ->
|
||||
*[true] borrow occurs
|
||||
[false] borrows occur
|
||||
} due to use of {$place} in closure"
|
||||
)]
|
||||
BorrowUsePlaceClosure {
|
||||
is_single_var: bool,
|
||||
place: String,
|
||||
#[primary_span]
|
||||
var_span: Span,
|
||||
},
|
||||
#[label(borrowck_var_borrow_by_use_in_coroutine)]
|
||||
#[label("borrow occurs due to use in coroutine")]
|
||||
BorrowUseInCoroutine {
|
||||
#[primary_span]
|
||||
var_span: Span,
|
||||
},
|
||||
#[label(borrowck_var_borrow_by_use_in_closure)]
|
||||
#[label("borrow occurs due to use in closure")]
|
||||
BorrowUseInClosure {
|
||||
#[primary_span]
|
||||
var_span: Span,
|
||||
},
|
||||
#[label(borrowck_var_move_by_use_in_coroutine)]
|
||||
#[label("move occurs due to use in coroutine")]
|
||||
MoveUseInCoroutine {
|
||||
#[primary_span]
|
||||
var_span: Span,
|
||||
},
|
||||
#[label(borrowck_var_move_by_use_in_closure)]
|
||||
#[label("move occurs due to use in closure")]
|
||||
MoveUseInClosure {
|
||||
#[primary_span]
|
||||
var_span: Span,
|
||||
},
|
||||
#[label(borrowck_var_first_borrow_by_use_place_in_coroutine)]
|
||||
#[label("first borrow occurs due to use of {$place} in coroutine")]
|
||||
FirstBorrowUsePlaceCoroutine {
|
||||
place: String,
|
||||
#[primary_span]
|
||||
var_span: Span,
|
||||
},
|
||||
#[label(borrowck_var_first_borrow_by_use_place_in_closure)]
|
||||
#[label("first borrow occurs due to use of {$place} in closure")]
|
||||
FirstBorrowUsePlaceClosure {
|
||||
place: String,
|
||||
#[primary_span]
|
||||
var_span: Span,
|
||||
},
|
||||
#[label(borrowck_var_second_borrow_by_use_place_in_coroutine)]
|
||||
#[label("second borrow occurs due to use of {$place} in coroutine")]
|
||||
SecondBorrowUsePlaceCoroutine {
|
||||
place: String,
|
||||
#[primary_span]
|
||||
var_span: Span,
|
||||
},
|
||||
#[label(borrowck_var_second_borrow_by_use_place_in_closure)]
|
||||
#[label("second borrow occurs due to use of {$place} in closure")]
|
||||
SecondBorrowUsePlaceClosure {
|
||||
place: String,
|
||||
#[primary_span]
|
||||
var_span: Span,
|
||||
},
|
||||
#[label(borrowck_var_mutable_borrow_by_use_place_in_closure)]
|
||||
#[label("mutable borrow occurs due to use of {$place} in closure")]
|
||||
MutableBorrowUsePlaceClosure {
|
||||
place: String,
|
||||
#[primary_span]
|
||||
var_span: Span,
|
||||
},
|
||||
#[label(borrowck_partial_var_move_by_use_in_coroutine)]
|
||||
#[label(
|
||||
"variable {$is_partial ->
|
||||
[true] partially moved
|
||||
*[false] moved
|
||||
} due to use in coroutine"
|
||||
)]
|
||||
PartialMoveUseInCoroutine {
|
||||
#[primary_span]
|
||||
var_span: Span,
|
||||
is_partial: bool,
|
||||
},
|
||||
#[label(borrowck_partial_var_move_by_use_in_closure)]
|
||||
#[label(
|
||||
"variable {$is_partial ->
|
||||
[true] partially moved
|
||||
*[false] moved
|
||||
} due to use in closure"
|
||||
)]
|
||||
PartialMoveUseInClosure {
|
||||
#[primary_span]
|
||||
var_span: Span,
|
||||
|
|
@ -282,34 +315,57 @@ pub(crate) enum CaptureVarCause {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(borrowck_cannot_move_when_borrowed, code = E0505)]
|
||||
#[diag("cannot move out of {$place ->
|
||||
[value] value
|
||||
*[other] {$place}
|
||||
} because it is 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(borrowck_move_label)]
|
||||
#[label(
|
||||
"move out of {$value_place ->
|
||||
[value] value
|
||||
*[other] {$value_place}
|
||||
} occurs here"
|
||||
)]
|
||||
pub span: Span,
|
||||
#[label]
|
||||
#[label(
|
||||
"borrow of {$borrow_place ->
|
||||
[value] value
|
||||
*[other] {$borrow_place}
|
||||
} occurs here"
|
||||
)]
|
||||
pub borrow_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(borrowck_opaque_type_lifetime_mismatch)]
|
||||
#[diag("opaque type used twice with different lifetimes")]
|
||||
pub(crate) struct LifetimeMismatchOpaqueParam<'tcx> {
|
||||
pub arg: GenericArg<'tcx>,
|
||||
pub prev: GenericArg<'tcx>,
|
||||
#[primary_span]
|
||||
#[label]
|
||||
#[note]
|
||||
#[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"
|
||||
)]
|
||||
pub span: Span,
|
||||
#[label(borrowck_prev_lifetime_label)]
|
||||
#[label("lifetime `{$prev}` previously used here")]
|
||||
pub prev_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum CaptureReasonLabel<'a> {
|
||||
#[label(borrowck_moved_due_to_call)]
|
||||
#[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
|
||||
}"
|
||||
)]
|
||||
Call {
|
||||
#[primary_span]
|
||||
fn_call_span: Span,
|
||||
|
|
@ -317,7 +373,15 @@ pub(crate) enum CaptureReasonLabel<'a> {
|
|||
is_partial: bool,
|
||||
is_loop_message: bool,
|
||||
},
|
||||
#[label(borrowck_moved_due_to_usage_in_operator)]
|
||||
#[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
|
||||
}"
|
||||
)]
|
||||
OperatorUse {
|
||||
#[primary_span]
|
||||
fn_call_span: Span,
|
||||
|
|
@ -325,7 +389,15 @@ pub(crate) enum CaptureReasonLabel<'a> {
|
|||
is_partial: bool,
|
||||
is_loop_message: bool,
|
||||
},
|
||||
#[label(borrowck_moved_due_to_implicit_into_iter_call)]
|
||||
#[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()`
|
||||
}"
|
||||
)]
|
||||
ImplicitCall {
|
||||
#[primary_span]
|
||||
fn_call_span: Span,
|
||||
|
|
@ -333,7 +405,15 @@ pub(crate) enum CaptureReasonLabel<'a> {
|
|||
is_partial: bool,
|
||||
is_loop_message: bool,
|
||||
},
|
||||
#[label(borrowck_moved_due_to_method_call)]
|
||||
#[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
|
||||
}"
|
||||
)]
|
||||
MethodCall {
|
||||
#[primary_span]
|
||||
fn_call_span: Span,
|
||||
|
|
@ -341,7 +421,15 @@ pub(crate) enum CaptureReasonLabel<'a> {
|
|||
is_partial: bool,
|
||||
is_loop_message: bool,
|
||||
},
|
||||
#[label(borrowck_moved_due_to_await)]
|
||||
#[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
|
||||
}"
|
||||
)]
|
||||
Await {
|
||||
#[primary_span]
|
||||
fn_call_span: Span,
|
||||
|
|
@ -349,7 +437,18 @@ pub(crate) enum CaptureReasonLabel<'a> {
|
|||
is_partial: bool,
|
||||
is_loop_message: bool,
|
||||
},
|
||||
#[label(borrowck_value_moved_here)]
|
||||
#[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] {\"\"}
|
||||
}"
|
||||
)]
|
||||
MovedHere {
|
||||
#[primary_span]
|
||||
move_span: Span,
|
||||
|
|
@ -357,7 +456,7 @@ pub(crate) enum CaptureReasonLabel<'a> {
|
|||
is_move_msg: bool,
|
||||
is_loop_message: bool,
|
||||
},
|
||||
#[label(borrowck_consider_borrow_type_contents)]
|
||||
#[label("help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents")]
|
||||
BorrowContent {
|
||||
#[primary_span]
|
||||
var_span: Span,
|
||||
|
|
@ -366,22 +465,22 @@ pub(crate) enum CaptureReasonLabel<'a> {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum CaptureReasonNote {
|
||||
#[note(borrowck_moved_a_fn_once_in_call)]
|
||||
#[note("this value implements `FnOnce`, which causes it to be moved when called")]
|
||||
FnOnceMoveInCall {
|
||||
#[primary_span]
|
||||
var_span: Span,
|
||||
},
|
||||
#[note(borrowck_calling_operator_moves)]
|
||||
#[note("calling this operator moves the value")]
|
||||
UnOpMoveByOperator {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[note(borrowck_calling_operator_moves_lhs)]
|
||||
#[note("calling this operator moves the left-hand side")]
|
||||
LhsMoveByOperator {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[note(borrowck_func_take_self_moved_place)]
|
||||
#[note("`{$func}` takes ownership of the receiver `self`, which moves {$place_name}")]
|
||||
FuncTakeSelf {
|
||||
func: String,
|
||||
place_name: String,
|
||||
|
|
@ -393,7 +492,7 @@ pub(crate) enum CaptureReasonNote {
|
|||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum CaptureReasonSuggest<'tcx> {
|
||||
#[suggestion(
|
||||
borrowck_suggest_iterate_over_slice,
|
||||
"consider iterating over a slice of the `{$ty}`'s content to avoid moving into the `for` loop",
|
||||
applicability = "maybe-incorrect",
|
||||
code = "&",
|
||||
style = "verbose"
|
||||
|
|
@ -404,7 +503,7 @@ pub(crate) enum CaptureReasonSuggest<'tcx> {
|
|||
span: Span,
|
||||
},
|
||||
#[suggestion(
|
||||
borrowck_suggest_create_fresh_reborrow,
|
||||
"consider reborrowing the `Pin` instead of moving it",
|
||||
applicability = "maybe-incorrect",
|
||||
code = ".as_mut()",
|
||||
style = "verbose"
|
||||
|
|
@ -417,13 +516,18 @@ pub(crate) enum CaptureReasonSuggest<'tcx> {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum CaptureArgLabel {
|
||||
#[label(borrowck_value_capture_here)]
|
||||
#[label(
|
||||
"value captured {$is_within ->
|
||||
[true] here by coroutine
|
||||
*[false] here
|
||||
}"
|
||||
)]
|
||||
Capture {
|
||||
is_within: bool,
|
||||
#[primary_span]
|
||||
args_span: Span,
|
||||
},
|
||||
#[label(borrowck_move_out_place_here)]
|
||||
#[label("{$place} is moved here")]
|
||||
MoveOutPlace {
|
||||
place: String,
|
||||
#[primary_span]
|
||||
|
|
@ -433,13 +537,17 @@ pub(crate) enum CaptureArgLabel {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum OnClosureNote<'a> {
|
||||
#[note(borrowck_closure_invoked_twice)]
|
||||
#[note(
|
||||
"closure cannot be invoked more than once because it moves the variable `{$place_name}` out of its environment"
|
||||
)]
|
||||
InvokedTwice {
|
||||
place_name: &'a str,
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[note(borrowck_closure_moved_twice)]
|
||||
#[note(
|
||||
"closure cannot be moved more than once as it is not `Copy` due to moving the variable `{$place_name}` out of its environment"
|
||||
)]
|
||||
MovedTwice {
|
||||
place_name: &'a str,
|
||||
#[primary_span]
|
||||
|
|
@ -449,7 +557,12 @@ pub(crate) enum OnClosureNote<'a> {
|
|||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum TypeNoCopy<'a, 'tcx> {
|
||||
#[label(borrowck_ty_no_impl_copy)]
|
||||
#[label(
|
||||
"{$is_partial_move ->
|
||||
[true] partial move
|
||||
*[false] move
|
||||
} occurs because {$place} has type `{$ty}`, which does not implement the `Copy` trait"
|
||||
)]
|
||||
Label {
|
||||
is_partial_move: bool,
|
||||
ty: Ty<'tcx>,
|
||||
|
|
@ -457,12 +570,24 @@ pub(crate) enum TypeNoCopy<'a, 'tcx> {
|
|||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[note(borrowck_ty_no_impl_copy)]
|
||||
#[note(
|
||||
"{$is_partial_move ->
|
||||
[true] partial move
|
||||
*[false] move
|
||||
} occurs because {$place} has type `{$ty}`, which does not implement the `Copy` trait"
|
||||
)]
|
||||
Note { is_partial_move: bool, ty: Ty<'tcx>, place: &'a str },
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(borrowck_simd_intrinsic_arg_const)]
|
||||
#[diag(
|
||||
"{$arg ->
|
||||
[1] 1st
|
||||
[2] 2nd
|
||||
[3] 3rd
|
||||
*[other] {$arg}th
|
||||
} argument of `{$intrinsic}` is required to be a `const` item"
|
||||
)]
|
||||
pub(crate) struct SimdIntrinsicArgConst {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
|
@ -471,8 +596,8 @@ pub(crate) struct SimdIntrinsicArgConst {
|
|||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(borrowck_tail_expr_drop_order)]
|
||||
#[diag("relative drop order changing in Rust 2024")]
|
||||
pub(crate) struct TailExprDropOrder {
|
||||
#[label]
|
||||
#[label("this temporary value will be dropped at the end of the block")]
|
||||
pub borrowed: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use tracing::debug;
|
|||
|
||||
use super::TypeChecker;
|
||||
use crate::constraints::OutlivesConstraintSet;
|
||||
use crate::polonius::PoloniusLivenessContext;
|
||||
use crate::polonius::PoloniusContext;
|
||||
use crate::region_infer::values::LivenessValues;
|
||||
use crate::universal_regions::UniversalRegions;
|
||||
|
||||
|
|
@ -48,7 +48,7 @@ pub(super) fn generate<'tcx>(
|
|||
if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() {
|
||||
let (_, boring_locals) =
|
||||
compute_relevant_live_locals(typeck.tcx(), &free_regions, typeck.body);
|
||||
typeck.polonius_liveness.as_mut().unwrap().boring_nll_locals =
|
||||
typeck.polonius_context.as_mut().unwrap().boring_nll_locals =
|
||||
boring_locals.into_iter().collect();
|
||||
free_regions = typeck.universal_regions.universal_regions_iter().collect();
|
||||
}
|
||||
|
|
@ -63,7 +63,7 @@ pub(super) fn generate<'tcx>(
|
|||
typeck.tcx(),
|
||||
&mut typeck.constraints.liveness_constraints,
|
||||
&typeck.universal_regions,
|
||||
&mut typeck.polonius_liveness,
|
||||
&mut typeck.polonius_context,
|
||||
typeck.body,
|
||||
);
|
||||
}
|
||||
|
|
@ -140,11 +140,11 @@ fn record_regular_live_regions<'tcx>(
|
|||
tcx: TyCtxt<'tcx>,
|
||||
liveness_constraints: &mut LivenessValues,
|
||||
universal_regions: &UniversalRegions<'tcx>,
|
||||
polonius_liveness: &mut Option<PoloniusLivenessContext>,
|
||||
polonius_context: &mut Option<PoloniusContext>,
|
||||
body: &Body<'tcx>,
|
||||
) {
|
||||
let mut visitor =
|
||||
LiveVariablesVisitor { tcx, liveness_constraints, universal_regions, polonius_liveness };
|
||||
LiveVariablesVisitor { tcx, liveness_constraints, universal_regions, polonius_context };
|
||||
for (bb, data) in body.basic_blocks.iter_enumerated() {
|
||||
visitor.visit_basic_block_data(bb, data);
|
||||
}
|
||||
|
|
@ -155,7 +155,7 @@ struct LiveVariablesVisitor<'a, 'tcx> {
|
|||
tcx: TyCtxt<'tcx>,
|
||||
liveness_constraints: &'a mut LivenessValues,
|
||||
universal_regions: &'a UniversalRegions<'tcx>,
|
||||
polonius_liveness: &'a mut Option<PoloniusLivenessContext>,
|
||||
polonius_context: &'a mut Option<PoloniusContext>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for LiveVariablesVisitor<'a, 'tcx> {
|
||||
|
|
@ -207,8 +207,8 @@ impl<'a, 'tcx> LiveVariablesVisitor<'a, 'tcx> {
|
|||
});
|
||||
|
||||
// When using `-Zpolonius=next`, we record the variance of each live region.
|
||||
if let Some(polonius_liveness) = self.polonius_liveness {
|
||||
polonius_liveness.record_live_region_variance(self.tcx, self.universal_regions, value);
|
||||
if let Some(polonius_context) = self.polonius_context {
|
||||
polonius_context.record_live_region_variance(self.tcx, self.universal_regions, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -622,8 +622,8 @@ impl<'tcx> LivenessContext<'_, '_, 'tcx> {
|
|||
});
|
||||
|
||||
// When using `-Zpolonius=next`, we record the variance of each live region.
|
||||
if let Some(polonius_liveness) = typeck.polonius_liveness.as_mut() {
|
||||
polonius_liveness.record_live_region_variance(
|
||||
if let Some(polonius_context) = typeck.polonius_context.as_mut() {
|
||||
polonius_context.record_live_region_variance(
|
||||
typeck.infcx.tcx,
|
||||
typeck.universal_regions,
|
||||
value,
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@ use tracing::{debug, instrument, trace};
|
|||
use crate::borrow_set::BorrowSet;
|
||||
use crate::constraints::{OutlivesConstraint, OutlivesConstraintSet};
|
||||
use crate::diagnostics::UniverseInfo;
|
||||
use crate::polonius::PoloniusContext;
|
||||
use crate::polonius::legacy::{PoloniusFacts, PoloniusLocationTable};
|
||||
use crate::polonius::{PoloniusContext, PoloniusLivenessContext};
|
||||
use crate::region_infer::TypeTest;
|
||||
use crate::region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices};
|
||||
use crate::session_diagnostics::{MoveUnsized, SimdIntrinsicArgConst};
|
||||
|
|
@ -139,8 +139,8 @@ pub(crate) fn type_check<'tcx>(
|
|||
|
||||
debug!(?normalized_inputs_and_output);
|
||||
|
||||
let polonius_liveness = if infcx.tcx.sess.opts.unstable_opts.polonius.is_next_enabled() {
|
||||
Some(PoloniusLivenessContext::default())
|
||||
let polonius_context = if infcx.tcx.sess.opts.unstable_opts.polonius.is_next_enabled() {
|
||||
Some(PoloniusContext::default())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
|
@ -162,7 +162,7 @@ pub(crate) fn type_check<'tcx>(
|
|||
borrow_set,
|
||||
constraints: &mut constraints,
|
||||
deferred_closure_requirements: &mut deferred_closure_requirements,
|
||||
polonius_liveness,
|
||||
polonius_context,
|
||||
};
|
||||
|
||||
typeck.check_user_type_annotations();
|
||||
|
|
@ -172,14 +172,7 @@ pub(crate) fn type_check<'tcx>(
|
|||
|
||||
liveness::generate(&mut typeck, &location_map, move_data);
|
||||
|
||||
// We're done with typeck, we can finalize the polonius liveness context for region inference.
|
||||
let polonius_context = typeck.polonius_liveness.take().map(|liveness_context| {
|
||||
PoloniusContext::create_from_liveness(
|
||||
liveness_context,
|
||||
infcx.num_region_vars(),
|
||||
typeck.constraints.liveness_constraints.points(),
|
||||
)
|
||||
});
|
||||
let polonius_context = typeck.polonius_context;
|
||||
|
||||
// In case type check encountered an error region, we suppress unhelpful extra
|
||||
// errors in by clearing out all outlives bounds that we may end up checking.
|
||||
|
|
@ -238,7 +231,7 @@ struct TypeChecker<'a, 'tcx> {
|
|||
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
|
||||
deferred_closure_requirements: &'a mut DeferredClosureRequirements<'tcx>,
|
||||
/// When using `-Zpolonius=next`, the liveness helper data used to create polonius constraints.
|
||||
polonius_liveness: Option<PoloniusLivenessContext>,
|
||||
polonius_context: Option<PoloniusContext>,
|
||||
}
|
||||
|
||||
/// Holder struct for passing results from MIR typeck to the rest of the non-lexical regions
|
||||
|
|
@ -775,7 +768,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
ty::BoundRegionKind::Anon => sym::anon,
|
||||
ty::BoundRegionKind::Named(def_id) => tcx.item_name(def_id),
|
||||
ty::BoundRegionKind::ClosureEnv => sym::env,
|
||||
ty::BoundRegionKind::NamedAnon(_) => {
|
||||
ty::BoundRegionKind::NamedForPrinting(_) => {
|
||||
bug!("only used for pretty printing")
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
|
|||
let infcx = self.type_checker.infcx;
|
||||
let mut lazy_universe = None;
|
||||
let delegate = FnMutDelegate {
|
||||
regions: &mut |br: ty::BoundRegion| {
|
||||
regions: &mut |br: ty::BoundRegion<'tcx>| {
|
||||
// The first time this closure is called, create a
|
||||
// new universe for the placeholders we will make
|
||||
// from here out.
|
||||
|
|
@ -191,10 +191,10 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
|
|||
|
||||
placeholder_reg
|
||||
},
|
||||
types: &mut |_bound_ty: ty::BoundTy| {
|
||||
types: &mut |_bound_ty: ty::BoundTy<'tcx>| {
|
||||
unreachable!("we only replace regions in nll_relate, not types")
|
||||
},
|
||||
consts: &mut |_bound_const: ty::BoundConst| {
|
||||
consts: &mut |_bound_const: ty::BoundConst<'tcx>| {
|
||||
unreachable!("we only replace regions in nll_relate, not consts")
|
||||
},
|
||||
};
|
||||
|
|
@ -218,7 +218,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
|
|||
let infcx = self.type_checker.infcx;
|
||||
let mut reg_map = FxHashMap::default();
|
||||
let delegate = FnMutDelegate {
|
||||
regions: &mut |br: ty::BoundRegion| {
|
||||
regions: &mut |br: ty::BoundRegion<'tcx>| {
|
||||
if let Some(ex_reg_var) = reg_map.get(&br) {
|
||||
*ex_reg_var
|
||||
} else {
|
||||
|
|
@ -230,10 +230,10 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
|
|||
ex_reg_var
|
||||
}
|
||||
},
|
||||
types: &mut |_bound_ty: ty::BoundTy| {
|
||||
types: &mut |_bound_ty: ty::BoundTy<'tcx>| {
|
||||
unreachable!("we only replace regions in nll_relate, not types")
|
||||
},
|
||||
consts: &mut |_bound_const: ty::BoundConst| {
|
||||
consts: &mut |_bound_const: ty::BoundConst<'tcx>| {
|
||||
unreachable!("we only replace regions in nll_relate, not consts")
|
||||
},
|
||||
};
|
||||
|
|
@ -268,7 +268,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
|
|||
ty::BoundRegionKind::Anon => sym::anon,
|
||||
ty::BoundRegionKind::Named(def_id) => self.type_checker.tcx().item_name(def_id),
|
||||
ty::BoundRegionKind::ClosureEnv => sym::env,
|
||||
ty::BoundRegionKind::NamedAnon(_) => bug!("only used for pretty printing"),
|
||||
ty::BoundRegionKind::NamedForPrinting(_) => bug!("only used for pretty printing"),
|
||||
};
|
||||
|
||||
if cfg!(debug_assertions) {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ rustc_data_structures = { path = "../rustc_data_structures" }
|
|||
rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_expand = { path = "../rustc_expand" }
|
||||
rustc_feature = { path = "../rustc_feature" }
|
||||
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||
rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_lexer = { path = "../rustc_lexer" }
|
||||
|
|
|
|||
|
|
@ -1,320 +0,0 @@
|
|||
builtin_macros_alloc_error_must_be_fn = alloc_error_handler must be a function
|
||||
builtin_macros_alloc_must_statics = allocators must be statics
|
||||
|
||||
builtin_macros_asm_attribute_not_supported =
|
||||
this attribute is not supported on assembly
|
||||
|
||||
builtin_macros_asm_clobber_abi = clobber_abi
|
||||
builtin_macros_asm_clobber_no_reg = asm with `clobber_abi` must specify explicit registers for outputs
|
||||
builtin_macros_asm_clobber_outputs = generic outputs
|
||||
|
||||
builtin_macros_asm_duplicate_arg = duplicate argument named `{$name}`
|
||||
.label = previously here
|
||||
.arg = duplicate argument
|
||||
|
||||
builtin_macros_asm_explicit_register_name = explicit register arguments cannot have names
|
||||
|
||||
builtin_macros_asm_mayunwind = asm labels are not allowed with the `may_unwind` option
|
||||
|
||||
builtin_macros_asm_modifier_invalid = asm template modifier must be a single character
|
||||
|
||||
builtin_macros_asm_mutually_exclusive = the `{$opt1}` and `{$opt2}` options are mutually exclusive
|
||||
|
||||
builtin_macros_asm_no_matched_argument_name = there is no argument named `{$name}`
|
||||
|
||||
builtin_macros_asm_noreturn = asm outputs are not allowed with the `noreturn` option
|
||||
|
||||
builtin_macros_asm_opt_already_provided = the `{$symbol}` option was already provided
|
||||
.label = this option was already provided
|
||||
.suggestion = remove this option
|
||||
|
||||
builtin_macros_asm_pos_after = positional arguments cannot follow named arguments or explicit register arguments
|
||||
.pos = positional argument
|
||||
.named = named argument
|
||||
.explicit = explicit register argument
|
||||
|
||||
builtin_macros_asm_pure_combine = the `pure` option must be combined with either `nomem` or `readonly`
|
||||
|
||||
builtin_macros_asm_pure_no_output = asm with the `pure` option must have at least one output
|
||||
|
||||
builtin_macros_asm_unsupported_clobber_abi = `clobber_abi` cannot be used with `{$macro_name}!`
|
||||
|
||||
builtin_macros_asm_unsupported_option = the `{$symbol}` option cannot be used with `{$macro_name}!`
|
||||
.label = the `{$symbol}` option is not meaningful for global-scoped inline assembly
|
||||
.suggestion = remove this option
|
||||
|
||||
builtin_macros_assert_missing_comma = unexpected string literal
|
||||
.suggestion = try adding a comma
|
||||
|
||||
builtin_macros_assert_requires_boolean = macro requires a boolean expression as an argument
|
||||
.label = boolean expression required
|
||||
|
||||
builtin_macros_assert_requires_expression = macro requires an expression as an argument
|
||||
.suggestion = try removing semicolon
|
||||
|
||||
builtin_macros_autodiff = autodiff must be applied to function
|
||||
builtin_macros_autodiff_missing_config = autodiff requires at least a name and mode
|
||||
builtin_macros_autodiff_mode_activity = {$act} can not be used in {$mode} Mode
|
||||
builtin_macros_autodiff_number_activities = expected {$expected} activities, but found {$found}
|
||||
builtin_macros_autodiff_ret_activity = invalid return activity {$act} in {$mode} Mode
|
||||
builtin_macros_autodiff_ty_activity = {$act} can not be used for this type
|
||||
builtin_macros_autodiff_unknown_activity = did not recognize Activity: `{$act}`
|
||||
|
||||
builtin_macros_autodiff_width = autodiff width must fit u32, but is {$width}
|
||||
|
||||
builtin_macros_avoid_att_syntax = avoid using `.att_syntax`, prefer using `options(att_syntax)` instead
|
||||
|
||||
builtin_macros_avoid_intel_syntax = avoid using `.intel_syntax`, Intel syntax is the default
|
||||
|
||||
builtin_macros_bad_derive_target = `derive` may only be applied to `struct`s, `enum`s and `union`s
|
||||
.label = not applicable here
|
||||
.label2 = not a `struct`, `enum` or `union`
|
||||
|
||||
builtin_macros_bench_sig = functions used as benches must have signature `fn(&mut Bencher) -> impl Termination`
|
||||
|
||||
|
||||
builtin_macros_cannot_derive_union = this trait cannot be derived for unions
|
||||
|
||||
builtin_macros_cfg_accessible_has_args = `cfg_accessible` path cannot accept arguments
|
||||
|
||||
builtin_macros_cfg_accessible_indeterminate = cannot determine whether the path is accessible or not
|
||||
|
||||
builtin_macros_cfg_accessible_literal_path = `cfg_accessible` path cannot be a literal
|
||||
builtin_macros_cfg_accessible_multiple_paths = multiple `cfg_accessible` paths are specified
|
||||
builtin_macros_cfg_accessible_unspecified_path = `cfg_accessible` path is not specified
|
||||
|
||||
builtin_macros_cfg_select_no_matches = none of the predicates in this `cfg_select` evaluated to true
|
||||
|
||||
builtin_macros_cfg_select_unreachable = unreachable predicate
|
||||
.label = always matches
|
||||
.label2 = this predicate is never reached
|
||||
|
||||
builtin_macros_coerce_pointee_requires_maybe_sized = `derive(CoercePointee)` requires `{$name}` to be marked `?Sized`
|
||||
|
||||
builtin_macros_coerce_pointee_requires_one_field = `CoercePointee` can only be derived on `struct`s with at least one field
|
||||
|
||||
builtin_macros_coerce_pointee_requires_one_generic = `CoercePointee` can only be derived on `struct`s that are generic over at least one type
|
||||
|
||||
builtin_macros_coerce_pointee_requires_one_pointee = exactly one generic type parameter must be marked as `#[pointee]` to derive `CoercePointee` traits
|
||||
|
||||
builtin_macros_coerce_pointee_requires_transparent = `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`
|
||||
|
||||
builtin_macros_coerce_pointee_too_many_pointees = only one type parameter can be marked as `#[pointee]` when deriving `CoercePointee` traits
|
||||
.label = here another type parameter is marked as `#[pointee]`
|
||||
|
||||
|
||||
builtin_macros_concat_bytes_array = cannot concatenate doubly nested array
|
||||
.note = byte strings are treated as arrays of bytes
|
||||
.help = try flattening the array
|
||||
|
||||
builtin_macros_concat_bytes_bad_repeat = repeat count is not a positive number
|
||||
|
||||
builtin_macros_concat_bytes_invalid = cannot concatenate {$lit_kind} literals
|
||||
.byte_char = try using a byte character
|
||||
.byte_str = try using a byte string
|
||||
.c_str = try using a null-terminated byte string
|
||||
.c_str_note = concatenating C strings is ambiguous about including the '\0'
|
||||
.number_array = try wrapping the number in an array
|
||||
|
||||
builtin_macros_concat_bytes_missing_literal = expected a byte literal
|
||||
.note = only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()`
|
||||
|
||||
builtin_macros_concat_bytes_non_u8 = numeric literal is not a `u8`
|
||||
|
||||
builtin_macros_concat_bytes_oob = numeric literal is out of bounds
|
||||
|
||||
builtin_macros_concat_bytestr = cannot concatenate a byte string literal
|
||||
builtin_macros_concat_c_str_lit = cannot concatenate a C string literal
|
||||
|
||||
builtin_macros_concat_missing_literal = expected a literal
|
||||
.note = only literals (like `"foo"`, `-42` and `3.14`) can be passed to `concat!()`
|
||||
|
||||
builtin_macros_default_arg = `#[default]` attribute does not accept a value
|
||||
.suggestion = try using `#[default]`
|
||||
|
||||
builtin_macros_derive_from_usage_note = `#[derive(From)]` can only be used on structs with exactly one field
|
||||
|
||||
builtin_macros_derive_from_wrong_field_count = `#[derive(From)]` used on a struct with {$multiple_fields ->
|
||||
[true] multiple fields
|
||||
*[false] no fields
|
||||
}
|
||||
|
||||
builtin_macros_derive_from_wrong_target = `#[derive(From)]` used on {$kind}
|
||||
|
||||
builtin_macros_derive_macro_call = `derive` cannot be used on items with type macros
|
||||
|
||||
builtin_macros_derive_path_args_list = traits in `#[derive(...)]` don't accept arguments
|
||||
.suggestion = remove the arguments
|
||||
|
||||
builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept values
|
||||
.suggestion = remove the value
|
||||
|
||||
builtin_macros_duplicate_macro_attribute = duplicated attribute
|
||||
|
||||
builtin_macros_eii_declaration_expected_list = `#[eii_declaration(...)]` expects a list of one or two elements
|
||||
builtin_macros_eii_declaration_expected_macro = `#[eii_declaration(...)]` is only valid on macros
|
||||
builtin_macros_eii_declaration_expected_unsafe = expected this argument to be "unsafe"
|
||||
.note = the second argument is optional
|
||||
|
||||
builtin_macros_eii_only_once = `#[{$name}]` can only be specified once
|
||||
.note = specified again here
|
||||
|
||||
builtin_macros_eii_shared_macro_expected_function = `#[{$name}]` is only valid on functions
|
||||
builtin_macros_eii_shared_macro_expected_max_one_argument = `#[{$name}]` expected no arguments or a single argument: `#[{$name}(default)]`
|
||||
builtin_macros_eii_shared_macro_in_statement_position = `#[{$name}]` can only be used on functions inside a module
|
||||
.label = `#[{$name}]` is used on this item, which is part of another item's local scope
|
||||
|
||||
builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time
|
||||
.cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead
|
||||
.cargo_typo = there is a similar Cargo environment variable: `{$suggested_var}`
|
||||
.custom = use `std::env::var({$var_expr})` to read the variable at run time
|
||||
|
||||
builtin_macros_env_not_unicode = environment variable `{$var}` is not a valid Unicode string
|
||||
|
||||
builtin_macros_env_takes_args = `env!()` takes 1 or 2 arguments
|
||||
|
||||
builtin_macros_expected_comma_in_list = expected token: `,`
|
||||
|
||||
builtin_macros_expected_one_cfg_pattern = expected 1 cfg-pattern
|
||||
|
||||
builtin_macros_expected_other = expected operand, {$is_inline_asm ->
|
||||
[false] options
|
||||
*[true] clobber_abi, options
|
||||
}, or additional template string
|
||||
|
||||
builtin_macros_export_macro_rules = cannot export macro_rules! macros from a `proc-macro` crate type currently
|
||||
|
||||
builtin_macros_format_add_missing_colon = add a colon before the format specifier
|
||||
|
||||
builtin_macros_format_duplicate_arg = duplicate argument named `{$ident}`
|
||||
.label1 = previously here
|
||||
.label2 = duplicate argument
|
||||
|
||||
builtin_macros_format_no_arg_named = there is no argument named `{$name}`
|
||||
.note = did you intend to capture a variable `{$name}` from the surrounding scope?
|
||||
.note2 = to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro
|
||||
|
||||
builtin_macros_format_pos_mismatch = {$n} positional {$n ->
|
||||
[one] argument
|
||||
*[more] arguments
|
||||
} in format string, but {$desc}
|
||||
|
||||
builtin_macros_format_positional_after_named = positional arguments cannot follow named arguments
|
||||
.label = positional arguments must be before named arguments
|
||||
.named_args = named argument
|
||||
|
||||
builtin_macros_format_redundant_args = redundant {$n ->
|
||||
[one] argument
|
||||
*[more] arguments
|
||||
}
|
||||
.help = {$n ->
|
||||
[one] the formatting string already captures the binding directly, it doesn't need to be included in the argument list
|
||||
*[more] the formatting strings already captures the bindings directly, they don't need to be included in the argument list
|
||||
}
|
||||
.note = {$n ->
|
||||
[one] the formatting specifier is referencing the binding already
|
||||
*[more] the formatting specifiers are referencing the bindings already
|
||||
}
|
||||
.suggestion = this can be removed
|
||||
|
||||
builtin_macros_format_remove_raw_ident = remove the `r#`
|
||||
|
||||
builtin_macros_format_reorder_format_parameter = did you mean `{$replacement}`?
|
||||
|
||||
builtin_macros_format_requires_string = requires at least a format string argument
|
||||
|
||||
builtin_macros_format_string_invalid = invalid format string: {$desc}
|
||||
.label = {$label1} in format string
|
||||
.note = {$note}
|
||||
.second_label = {$label}
|
||||
|
||||
builtin_macros_format_unknown_trait = unknown format trait `{$ty}`
|
||||
.note = the only appropriate formatting traits are:
|
||||
- ``, which uses the `Display` trait
|
||||
- `?`, which uses the `Debug` trait
|
||||
- `e`, which uses the `LowerExp` trait
|
||||
- `E`, which uses the `UpperExp` trait
|
||||
- `o`, which uses the `Octal` trait
|
||||
- `p`, which uses the `Pointer` trait
|
||||
- `b`, which uses the `Binary` trait
|
||||
- `x`, which uses the `LowerHex` trait
|
||||
- `X`, which uses the `UpperHex` trait
|
||||
.suggestion = use the `{$trait_name}` trait
|
||||
|
||||
builtin_macros_format_unused_arg = {$named ->
|
||||
[true] named argument
|
||||
*[false] argument
|
||||
} never used
|
||||
|
||||
builtin_macros_format_unused_args = multiple unused formatting arguments
|
||||
.label = multiple missing formatting specifiers
|
||||
|
||||
builtin_macros_format_use_positional = consider using a positional formatting argument instead
|
||||
|
||||
builtin_macros_incomplete_include = include macro expected single expression in source
|
||||
|
||||
builtin_macros_multiple_default_attrs = multiple `#[default]` attributes
|
||||
.note = only one `#[default]` attribute is needed
|
||||
.label = `#[default]` used here
|
||||
.label_again = `#[default]` used again here
|
||||
.help = try removing {$only_one ->
|
||||
[true] this
|
||||
*[false] these
|
||||
}
|
||||
|
||||
builtin_macros_multiple_defaults = multiple declared defaults
|
||||
.label = first default
|
||||
.additional = additional default
|
||||
.note = only one variant can be default
|
||||
.suggestion = make `{$ident}` default
|
||||
|
||||
builtin_macros_naked_functions_testing_attribute =
|
||||
cannot use `#[unsafe(naked)]` with testing attributes
|
||||
.label = function marked with testing attribute here
|
||||
.naked_attribute = `#[unsafe(naked)]` is incompatible with testing attributes
|
||||
|
||||
builtin_macros_no_default_variant = `#[derive(Default)]` on enum with no `#[default]`
|
||||
.label = this enum needs a unit variant marked with `#[default]`
|
||||
.suggestion = make this unit variant default by placing `#[default]` on it
|
||||
|
||||
builtin_macros_non_exhaustive_default = default variant must be exhaustive
|
||||
.label = declared `#[non_exhaustive]` here
|
||||
.help = consider a manual implementation of `Default`
|
||||
|
||||
builtin_macros_non_generic_pointee = the `#[pointee]` attribute may only be used on generic parameters
|
||||
|
||||
builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants{$post}
|
||||
.help = consider a manual implementation of `Default`
|
||||
|
||||
builtin_macros_only_one_argument = {$name} takes 1 argument
|
||||
|
||||
builtin_macros_proc_macro = `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]`
|
||||
|
||||
builtin_macros_proc_macro_attribute_only_usable_with_crate_type = the `#[{$path}]` attribute is only usable with crates of the `proc-macro` crate type
|
||||
|
||||
builtin_macros_requires_cfg_pattern =
|
||||
macro requires a cfg-pattern as an argument
|
||||
.label = cfg-pattern required
|
||||
|
||||
builtin_macros_source_utils_expected_item = expected item, found `{$token}`
|
||||
|
||||
builtin_macros_takes_no_arguments = {$name} takes no arguments
|
||||
|
||||
builtin_macros_test_bad_fn = {$kind} functions cannot be used for tests
|
||||
.label = `{$kind}` because of this
|
||||
|
||||
builtin_macros_test_case_non_item = `#[test_case]` attribute is only allowed on items
|
||||
|
||||
builtin_macros_test_runner_invalid = `test_runner` argument must be a path
|
||||
builtin_macros_test_runner_nargs = `#![test_runner(..)]` accepts exactly 1 argument
|
||||
|
||||
builtin_macros_tests_not_support = building tests with panic=abort is not supported without `-Zpanic_abort_tests`
|
||||
|
||||
builtin_macros_trace_macros = trace_macros! accepts only `true` or `false`
|
||||
|
||||
builtin_macros_unexpected_lit = expected path to a trait, found literal
|
||||
.label = not a trait
|
||||
.str_lit = try using `#[derive({$sym})]`
|
||||
.other = for example, write `#[derive(Debug)]` for `Debug`
|
||||
|
||||
builtin_macros_unnameable_test_items = cannot test inner items
|
||||
|
|
@ -43,7 +43,7 @@ pub(crate) fn expand(
|
|||
|
||||
// Generate anonymous constant serving as container for the allocator methods.
|
||||
let const_ty = ecx.ty(sig_span, TyKind::Tup(ThinVec::new()));
|
||||
let const_body = ast::ConstItemRhs::Body(ecx.expr_block(ecx.block(span, stmts)));
|
||||
let const_body = ast::ConstItemRhsKind::new_body(ecx.expr_block(ecx.block(span, stmts)));
|
||||
let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body);
|
||||
let const_item = if is_stmt {
|
||||
Annotatable::Stmt(Box::new(ecx.stmt_item(span, const_item)))
|
||||
|
|
|
|||
|
|
@ -288,6 +288,18 @@ fn expand_preparsed_asm(
|
|||
let msg = "asm template must be a string literal";
|
||||
let template_sp = template_expr.span;
|
||||
let template_is_mac_call = matches!(template_expr.kind, ast::ExprKind::MacCall(_));
|
||||
|
||||
// Gets the span inside `template_sp` corresponding to the given range
|
||||
let span_in_template = |range: std::ops::Range<usize>| -> Span {
|
||||
if template_is_mac_call {
|
||||
// When the template is a macro call we can't reliably get inner spans
|
||||
// so just use the entire template span (see ICEs #129503, #131292)
|
||||
template_sp
|
||||
} else {
|
||||
template_sp.from_inner(InnerSpan::new(range.start, range.end))
|
||||
}
|
||||
};
|
||||
|
||||
let ExprToSpannedString {
|
||||
symbol: template_str,
|
||||
style: template_style,
|
||||
|
|
@ -382,13 +394,8 @@ fn expand_preparsed_asm(
|
|||
|
||||
if !parser.errors.is_empty() {
|
||||
let err = parser.errors.remove(0);
|
||||
let err_sp = if template_is_mac_call {
|
||||
// If the template is a macro call we can't reliably point to the error's
|
||||
// span so just use the template's span as the error span (fixes #129503)
|
||||
template_span
|
||||
} else {
|
||||
template_span.from_inner(InnerSpan::new(err.span.start, err.span.end))
|
||||
};
|
||||
|
||||
let err_sp = span_in_template(err.span);
|
||||
|
||||
let msg = format!("invalid asm template string: {}", err.description);
|
||||
let mut e = ecx.dcx().struct_span_err(err_sp, msg);
|
||||
|
|
@ -397,8 +404,7 @@ fn expand_preparsed_asm(
|
|||
e.note(note);
|
||||
}
|
||||
if let Some((label, span)) = err.secondary_label {
|
||||
let err_sp = template_span.from_inner(InnerSpan::new(span.start, span.end));
|
||||
e.span_label(err_sp, label);
|
||||
e.span_label(span_in_template(span), label);
|
||||
}
|
||||
let guar = e.emit();
|
||||
return ExpandResult::Ready(Err(guar));
|
||||
|
|
@ -477,8 +483,7 @@ fn expand_preparsed_asm(
|
|||
ecx.dcx()
|
||||
.create_err(errors::AsmNoMatchedArgumentName {
|
||||
name: name.to_owned(),
|
||||
span: template_span
|
||||
.from_inner(InnerSpan::new(span.start, span.end)),
|
||||
span: span_in_template(span),
|
||||
})
|
||||
.emit();
|
||||
None
|
||||
|
|
@ -490,11 +495,7 @@ fn expand_preparsed_asm(
|
|||
let mut chars = arg.format.ty.chars();
|
||||
let mut modifier = chars.next();
|
||||
if chars.next().is_some() {
|
||||
let span = arg
|
||||
.format
|
||||
.ty_span
|
||||
.map(|sp| template_sp.from_inner(InnerSpan::new(sp.start, sp.end)))
|
||||
.unwrap_or(template_sp);
|
||||
let span = arg.format.ty_span.map(span_in_template).unwrap_or(template_sp);
|
||||
ecx.dcx().emit_err(errors::AsmModifierInvalid { span });
|
||||
modifier = None;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpa
|
|||
use rustc_hir::attrs::CfgEntry;
|
||||
use rustc_hir::{AttrPath, Target};
|
||||
use rustc_parse::exp;
|
||||
use rustc_parse::parser::Recovery;
|
||||
use rustc_span::{ErrorGuaranteed, Span, sym};
|
||||
|
||||
use crate::errors;
|
||||
|
|
@ -42,7 +43,7 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result<CfgEntry,
|
|||
|
||||
let meta = MetaItemOrLitParser::parse_single(
|
||||
&mut parser,
|
||||
ShouldEmit::ErrorsAndLints { recover: true },
|
||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
|
||||
)
|
||||
.map_err(|diag| diag.emit())?;
|
||||
let cfg = AttributeParser::parse_single_args(
|
||||
|
|
@ -58,7 +59,7 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result<CfgEntry,
|
|||
// Doesn't matter what the target actually is here.
|
||||
Target::Crate,
|
||||
Some(cx.ecfg.features),
|
||||
ShouldEmit::ErrorsAndLints { recover: true },
|
||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
|
||||
&meta,
|
||||
parse_cfg_entry,
|
||||
&CFG_TEMPLATE,
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{Expr, ast};
|
||||
use rustc_attr_parsing as attr;
|
||||
use rustc_attr_parsing::{
|
||||
CfgSelectBranches, CfgSelectPredicate, EvalConfigResult, parse_cfg_select,
|
||||
};
|
||||
use rustc_attr_parsing::{CfgSelectBranches, EvalConfigResult, parse_cfg_select};
|
||||
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult};
|
||||
use rustc_span::{Ident, Span, sym};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::errors::{CfgSelectNoMatches, CfgSelectUnreachable};
|
||||
use crate::errors::CfgSelectNoMatches;
|
||||
|
||||
/// This intermediate structure is used to emit parse errors for the branches that are not chosen.
|
||||
/// The `MacResult` instance below parses all branches, emitting any errors it encounters, but only
|
||||
|
|
@ -75,18 +73,6 @@ pub(super) fn expand_cfg_select<'cx>(
|
|||
ecx.current_expansion.lint_node_id,
|
||||
) {
|
||||
Ok(mut branches) => {
|
||||
if let Some((underscore, _, _)) = branches.wildcard {
|
||||
// Warn for every unreachable predicate. We store the fully parsed branch for rustfmt.
|
||||
for (predicate, _, _) in &branches.unreachable {
|
||||
let span = match predicate {
|
||||
CfgSelectPredicate::Wildcard(underscore) => underscore.span,
|
||||
CfgSelectPredicate::Cfg(cfg) => cfg.span(),
|
||||
};
|
||||
let err = CfgSelectUnreachable { span, wildcard_span: underscore.span };
|
||||
ecx.dcx().emit_warn(err);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((selected_tts, selected_span)) = branches.pop_first_match(|cfg| {
|
||||
matches!(attr::eval_config_entry(&ecx.sess, cfg), EvalConfigResult::True)
|
||||
}) {
|
||||
|
|
|
|||
|
|
@ -463,44 +463,44 @@ impl<'a, 'b> rustc_ast::visit::Visitor<'a> for AlwaysErrorOnGenericParam<'a, 'b>
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_coerce_pointee_requires_transparent, code = E0802)]
|
||||
#[diag("`CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`", code = E0802)]
|
||||
struct RequireTransparent {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_coerce_pointee_requires_one_field, code = E0802)]
|
||||
#[diag("`CoercePointee` can only be derived on `struct`s with at least one field", code = E0802)]
|
||||
struct RequireOneField {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_coerce_pointee_requires_one_generic, code = E0802)]
|
||||
#[diag("`CoercePointee` can only be derived on `struct`s that are generic over at least one type", code = E0802)]
|
||||
struct RequireOneGeneric {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_coerce_pointee_requires_one_pointee, code = E0802)]
|
||||
#[diag("exactly one generic type parameter must be marked as `#[pointee]` to derive `CoercePointee` traits", code = E0802)]
|
||||
struct RequireOnePointee {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_coerce_pointee_too_many_pointees, code = E0802)]
|
||||
#[diag("only one type parameter can be marked as `#[pointee]` when deriving `CoercePointee` traits", code = E0802)]
|
||||
struct TooManyPointees {
|
||||
#[primary_span]
|
||||
one: Span,
|
||||
#[label]
|
||||
#[label("here another type parameter is marked as `#[pointee]`")]
|
||||
another: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_coerce_pointee_requires_maybe_sized, code = E0802)]
|
||||
#[diag("`derive(CoercePointee)` requires `{$name}` to be marked `?Sized`", code = E0802)]
|
||||
struct RequiresMaybeSized {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
|
|
|
|||
|
|
@ -540,6 +540,7 @@ impl<'a> TraitDef<'a> {
|
|||
.filter(|a| {
|
||||
a.has_any_name(&[
|
||||
sym::allow,
|
||||
sym::expect,
|
||||
sym::warn,
|
||||
sym::deny,
|
||||
sym::forbid,
|
||||
|
|
@ -638,27 +639,27 @@ impl<'a> TraitDef<'a> {
|
|||
GenericParamKind::Type { .. } => {
|
||||
// Extra restrictions on the generics parameters to the
|
||||
// type being derived upon.
|
||||
let span = param.ident.span.with_ctxt(ctxt);
|
||||
let bounds: Vec<_> = self
|
||||
.additional_bounds
|
||||
.iter()
|
||||
.map(|p| {
|
||||
cx.trait_bound(
|
||||
p.to_path(cx, self.span, type_ident, generics),
|
||||
self.is_const,
|
||||
)
|
||||
cx.trait_bound(p.to_path(cx, span, type_ident, generics), self.is_const)
|
||||
})
|
||||
.chain(
|
||||
// Add a bound for the current trait.
|
||||
self.skip_path_as_bound
|
||||
.not()
|
||||
.then(|| cx.trait_bound(trait_path.clone(), self.is_const)),
|
||||
self.skip_path_as_bound.not().then(|| {
|
||||
let mut trait_path = trait_path.clone();
|
||||
trait_path.span = span;
|
||||
cx.trait_bound(trait_path, self.is_const)
|
||||
}),
|
||||
)
|
||||
.chain({
|
||||
// Add a `Copy` bound if required.
|
||||
if is_packed && self.needs_copy_as_bound_if_packed {
|
||||
let p = deriving::path_std!(marker::Copy);
|
||||
Some(cx.trait_bound(
|
||||
p.to_path(cx, self.span, type_ident, generics),
|
||||
p.to_path(cx, span, type_ident, generics),
|
||||
self.is_const,
|
||||
))
|
||||
} else {
|
||||
|
|
@ -671,7 +672,7 @@ impl<'a> TraitDef<'a> {
|
|||
)
|
||||
.collect();
|
||||
|
||||
cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, bounds, None)
|
||||
cx.typaram(span, param.ident, bounds, None)
|
||||
}
|
||||
GenericParamKind::Const { ty, span, .. } => {
|
||||
let const_nodefault_kind = GenericParamKind::Const {
|
||||
|
|
@ -791,7 +792,8 @@ impl<'a> TraitDef<'a> {
|
|||
.collect();
|
||||
|
||||
// Create the type of `self`.
|
||||
let path = cx.path_all(self.span, false, vec![type_ident], self_params);
|
||||
let path =
|
||||
cx.path_all(type_ident.span.with_ctxt(ctxt), false, vec![type_ident], self_params);
|
||||
let self_type = cx.ty_path(path);
|
||||
let rustc_const_unstable =
|
||||
cx.path_ident(self.span, Ident::new(sym::rustc_const_unstable, self.span));
|
||||
|
|
|
|||
|
|
@ -232,7 +232,7 @@ fn generate_default_impl(
|
|||
span,
|
||||
underscore,
|
||||
unit,
|
||||
ast::ConstItemRhs::Body(ecx.expr_block(ecx.block(span, stmts))),
|
||||
ast::ConstItemRhsKind::new_body(ecx.expr_block(ecx.block(span, stmts))),
|
||||
)
|
||||
};
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -160,6 +160,7 @@ fn make_format_args(
|
|||
ecx: &mut ExtCtxt<'_>,
|
||||
input: MacroInput,
|
||||
append_newline: bool,
|
||||
macro_span: Span,
|
||||
) -> ExpandResult<Result<FormatArgs, ErrorGuaranteed>, ()> {
|
||||
let msg = "format argument must be a string literal";
|
||||
let unexpanded_fmt_span = input.fmtstr.span;
|
||||
|
|
@ -333,6 +334,23 @@ fn make_format_args(
|
|||
let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end));
|
||||
e.sugg_ = Some(errors::InvalidFormatStringSuggestion::AddMissingColon { span });
|
||||
}
|
||||
parse::Suggestion::UseRustDebugPrintingMacro => {
|
||||
// This targets `println!("{=}", x);` and `println!("{0=}", x);`
|
||||
if let [arg] = args.all_args() {
|
||||
let expr_span = arg.expr.span;
|
||||
if let Ok(expr_snippet) = ecx.source_map().span_to_snippet(expr_span) {
|
||||
let replacement = format!("{}!({})", "dbg", expr_snippet);
|
||||
|
||||
let call_span = macro_span.source_callsite();
|
||||
e.sugg_ = Some(
|
||||
errors::InvalidFormatStringSuggestion::UseRustDebugPrintingMacro {
|
||||
macro_span: call_span,
|
||||
replacement,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let guar = ecx.dcx().emit_err(e);
|
||||
return ExpandResult::Ready(Err(guar));
|
||||
|
|
@ -1048,7 +1066,7 @@ fn expand_format_args_impl<'cx>(
|
|||
sp = ecx.with_def_site_ctxt(sp);
|
||||
ExpandResult::Ready(match parse_args(ecx, sp, tts) {
|
||||
Ok(input) => {
|
||||
let ExpandResult::Ready(mac) = make_format_args(ecx, input, nl) else {
|
||||
let ExpandResult::Ready(mac) = make_format_args(ecx, input, nl, sp) else {
|
||||
return ExpandResult::Retry(());
|
||||
};
|
||||
match mac {
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ pub(crate) fn expand(
|
|||
|
||||
// Generate anonymous constant serving as container for the allocator methods.
|
||||
let const_ty = ecx.ty(ty_span, TyKind::Tup(ThinVec::new()));
|
||||
let const_body = ast::ConstItemRhs::Body(ecx.expr_block(ecx.block(span, stmts)));
|
||||
let const_body = ast::ConstItemRhsKind::new_body(ecx.expr_block(ecx.block(span, stmts)));
|
||||
let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body);
|
||||
let const_item = if is_stmt {
|
||||
Annotatable::Stmt(Box::new(ecx.stmt_item(span, const_item)))
|
||||
|
|
@ -128,11 +128,15 @@ impl AllocFnFactory<'_, '_> {
|
|||
|
||||
let usize = self.cx.path_ident(self.span, Ident::new(sym::usize, self.span));
|
||||
let ty_usize = self.cx.ty_path(usize);
|
||||
args.push(self.cx.param(self.span, size, ty_usize.clone()));
|
||||
args.push(self.cx.param(self.span, align, ty_usize));
|
||||
args.push(self.cx.param(self.span, size, ty_usize));
|
||||
let ty_align = self.ptr_alignment();
|
||||
args.push(self.cx.param(self.span, align, ty_align));
|
||||
|
||||
let layout_new =
|
||||
self.cx.std_path(&[sym::alloc, sym::Layout, sym::from_size_align_unchecked]);
|
||||
let layout_new = self.cx.std_path(&[
|
||||
sym::alloc,
|
||||
sym::Layout,
|
||||
sym::from_size_alignment_unchecked,
|
||||
]);
|
||||
let layout_new = self.cx.expr_path(self.cx.path(self.span, layout_new));
|
||||
let size = self.cx.expr_ident(self.span, size);
|
||||
let align = self.cx.expr_ident(self.span, align);
|
||||
|
|
@ -175,6 +179,12 @@ impl AllocFnFactory<'_, '_> {
|
|||
self.cx.ty_path(usize)
|
||||
}
|
||||
|
||||
fn ptr_alignment(&self) -> Box<Ty> {
|
||||
let path = self.cx.std_path(&[sym::ptr, sym::Alignment]);
|
||||
let path = self.cx.path(self.span, path);
|
||||
self.cx.ty_path(path)
|
||||
}
|
||||
|
||||
fn ptr_u8(&self) -> Box<Ty> {
|
||||
let u8 = self.cx.path_ident(self.span, Ident::new(sym::u8, self.span));
|
||||
let ty_u8 = self.cx.ty_path(u8);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![feature(assert_matches)]
|
||||
#![cfg_attr(bootstrap, feature(assert_matches))]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(if_let_guard)]
|
||||
|
|
@ -57,8 +57,6 @@ pub mod standard_library_imports;
|
|||
pub mod test_harness;
|
||||
pub mod util;
|
||||
|
||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||
|
||||
pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
|
||||
let mut register = |name, kind| resolver.register_builtin_macro(name, kind);
|
||||
macro register_bang($($name:ident: $f:expr,)*) {
|
||||
|
|
|
|||
|
|
@ -385,7 +385,7 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> Box<ast::Item> {
|
|||
cx.attr_nested_word(sym::allow, sym::deprecated, span),
|
||||
]);
|
||||
|
||||
let block = ast::ConstItemRhs::Body(cx.expr_block(
|
||||
let block = ast::ConstItemRhsKind::new_body(cx.expr_block(
|
||||
cx.block(span, thin_vec![cx.stmt_item(span, krate), cx.stmt_item(span, decls_static)]),
|
||||
));
|
||||
|
||||
|
|
|
|||
|
|
@ -289,7 +289,7 @@ pub(crate) fn expand_test_or_bench(
|
|||
ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))),
|
||||
define_opaque: None,
|
||||
// test::TestDescAndFn {
|
||||
rhs: Some(ast::ConstItemRhs::Body(
|
||||
rhs_kind: ast::ConstItemRhsKind::new_body(
|
||||
cx.expr_struct(
|
||||
sp,
|
||||
test_path("TestDescAndFn"),
|
||||
|
|
@ -371,7 +371,7 @@ pub(crate) fn expand_test_or_bench(
|
|||
field("testfn", test_fn), // }
|
||||
],
|
||||
), // }
|
||||
)),
|
||||
),
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -8,10 +8,11 @@ use rustc_ast::entry::EntryPointType;
|
|||
use rustc_ast::mut_visit::*;
|
||||
use rustc_ast::visit::Visitor;
|
||||
use rustc_ast::{ModKind, attr};
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_attr_parsing::AttributeParser;
|
||||
use rustc_expand::base::{ExtCtxt, ResolverExpand};
|
||||
use rustc_expand::expand::{AstFragment, ExpansionConfig};
|
||||
use rustc_feature::Features;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::lint::builtin::UNNAMEABLE_TEST_ITEMS;
|
||||
use rustc_span::hygiene::{AstPass, SyntaxContext, Transparency};
|
||||
|
|
@ -60,7 +61,7 @@ pub fn inject(
|
|||
|
||||
// Do this here so that the test_runner crate attribute gets marked as used
|
||||
// even in non-test builds
|
||||
let test_runner = get_test_runner(dcx, krate);
|
||||
let test_runner = get_test_runner(sess, features, krate);
|
||||
|
||||
if sess.is_test_crate() {
|
||||
let panic_strategy = match (panic_strategy, sess.opts.unstable_opts.panic_abort_tests) {
|
||||
|
|
@ -386,20 +387,16 @@ fn get_test_name(i: &ast::Item) -> Option<Symbol> {
|
|||
attr::first_attr_value_str_by_name(&i.attrs, sym::rustc_test_marker)
|
||||
}
|
||||
|
||||
fn get_test_runner(dcx: DiagCtxtHandle<'_>, krate: &ast::Crate) -> Option<ast::Path> {
|
||||
let test_attr = attr::find_by_name(&krate.attrs, sym::test_runner)?;
|
||||
let meta_list = test_attr.meta_item_list()?;
|
||||
let span = test_attr.span;
|
||||
match &*meta_list {
|
||||
[single] => match single.meta_item() {
|
||||
Some(meta_item) if meta_item.is_word() => return Some(meta_item.path.clone()),
|
||||
_ => {
|
||||
dcx.emit_err(errors::TestRunnerInvalid { span });
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
dcx.emit_err(errors::TestRunnerNargs { span });
|
||||
}
|
||||
fn get_test_runner(sess: &Session, features: &Features, krate: &ast::Crate) -> Option<ast::Path> {
|
||||
match AttributeParser::parse_limited(
|
||||
sess,
|
||||
&krate.attrs,
|
||||
sym::test_runner,
|
||||
krate.spans.inner_span,
|
||||
krate.id,
|
||||
Some(features),
|
||||
) {
|
||||
Some(rustc_hir::Attribute::Parsed(AttributeKind::TestRunner(path))) => Some(path),
|
||||
_ => None,
|
||||
}
|
||||
None
|
||||
}
|
||||
|
|
|
|||
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