Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8489f1adbe | ||
|
|
e936dad761 | ||
|
|
febf9f5047 | ||
|
|
b4d644b3b6 | ||
|
|
216757db18 | ||
|
|
f56b846f39 | ||
|
|
74ab15caf5 | ||
|
|
847a841b73 | ||
|
|
ef0fb8a256 | ||
|
|
7892916367 | ||
|
|
ae9f3e75f1 | ||
|
|
6a605e2640 |
2
.gitmodules
vendored
2
.gitmodules
vendored
@@ -25,7 +25,7 @@
|
||||
[submodule "src/llvm-project"]
|
||||
path = src/llvm-project
|
||||
url = https://github.com/rust-lang/llvm-project.git
|
||||
branch = rustc/22.1-2026-03-22
|
||||
branch = rustc/22.1-2026-01-27
|
||||
shallow = true
|
||||
[submodule "src/doc/embedded-book"]
|
||||
path = src/doc/embedded-book
|
||||
|
||||
10
.mailmap
10
.mailmap
@@ -258,11 +258,11 @@ Greg V <greg@unrelenting.technology>
|
||||
Gregor Peach <gregorpeach@gmail.com>
|
||||
Grzegorz Bartoszek <grzegorz.bartoszek@thaumatec.com>
|
||||
Guanqun Lu <guanqun.lu@gmail.com>
|
||||
Guillaume Gomez <contact@guillaume-gomez.fr>
|
||||
Guillaume Gomez <contact@guillaume-gomez.fr> Guillaume Gomez <guillaume1.gomez@gmail.com>
|
||||
Guillaume Gomez <contact@guillaume-gomez.fr> ggomez <ggomez@ggo.ifr.lan>
|
||||
Guillaume Gomez <contact@guillaume-gomez.fr> Guillaume Gomez <ggomez@ggo.ifr.lan>
|
||||
Guillaume Gomez <contact@guillaume-gomez.fr> Guillaume Gomez <guillaume.gomez@huawei.com>
|
||||
Guillaume Gomez <guillaume1.gomez@gmail.com>
|
||||
Guillaume Gomez <guillaume1.gomez@gmail.com> ggomez <ggomez@ggo.ifr.lan>
|
||||
Guillaume Gomez <guillaume1.gomez@gmail.com> Guillaume Gomez <ggomez@ggo.ifr.lan>
|
||||
Guillaume Gomez <guillaume1.gomez@gmail.com> Guillaume Gomez <guillaume.gomez@huawei.com>
|
||||
Guillaume Gomez <guillaume1.gomez@gmail.com> Guillaume Gomez <contact@guillaume-gomez.fr>
|
||||
gnzlbg <gonzalobg88@gmail.com> <gnzlbg@users.noreply.github.com>
|
||||
hamidreza kalbasi <hamidrezakalbasi@protonmail.com>
|
||||
Hanna Kruppe <hanna.kruppe@gmail.com> <robin.kruppe@gmail.com>
|
||||
|
||||
370
Cargo.lock
370
Cargo.lock
@@ -199,7 +199,7 @@ dependencies = [
|
||||
"rustc-hash 2.1.1",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -257,7 +257,7 @@ dependencies = [
|
||||
"miniz_oxide",
|
||||
"object 0.36.7",
|
||||
"rustc-demangle",
|
||||
"windows-targets",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -396,7 +396,7 @@ checksum = "89385e82b5d1821d2219e0b095efa2cc1f246cbf99080f3be46a1a85c0d392d9"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -573,6 +573,7 @@ checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
|
||||
dependencies = [
|
||||
"iana-time-zone",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
@@ -634,10 +635,10 @@ version = "4.5.49"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -648,11 +649,11 @@ checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
|
||||
|
||||
[[package]]
|
||||
name = "clippy"
|
||||
version = "0.1.97"
|
||||
version = "0.1.96"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"askama",
|
||||
"cargo_metadata 0.23.1",
|
||||
"cargo_metadata 0.18.1",
|
||||
"clippy_config",
|
||||
"clippy_lints",
|
||||
"clippy_lints_internal",
|
||||
@@ -675,7 +676,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clippy_config"
|
||||
version = "0.1.97"
|
||||
version = "0.1.96"
|
||||
dependencies = [
|
||||
"clippy_utils",
|
||||
"itertools",
|
||||
@@ -699,10 +700,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clippy_lints"
|
||||
version = "0.1.97"
|
||||
version = "0.1.96"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"cargo_metadata 0.23.1",
|
||||
"cargo_metadata 0.18.1",
|
||||
"clippy_config",
|
||||
"clippy_utils",
|
||||
"declare_clippy_lint",
|
||||
@@ -731,7 +732,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clippy_utils"
|
||||
version = "0.1.97"
|
||||
version = "0.1.96"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"itertools",
|
||||
@@ -756,7 +757,7 @@ checksum = "af491d569909a7e4dee0ad7db7f5341fef5c614d5b8ec8cf765732aba3cff681"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"termcolor",
|
||||
"unicode-width 0.1.14",
|
||||
"unicode-width 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -767,6 +768,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"similar",
|
||||
"spdx-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -802,7 +804,7 @@ dependencies = [
|
||||
"nom",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -825,11 +827,21 @@ checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
||||
|
||||
[[package]]
|
||||
name = "colored"
|
||||
version = "3.1.1"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34"
|
||||
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
"lazy_static",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colored"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -845,7 +857,7 @@ dependencies = [
|
||||
"anstyle-svg",
|
||||
"build_helper",
|
||||
"camino",
|
||||
"colored",
|
||||
"colored 2.2.0",
|
||||
"diff",
|
||||
"getopts",
|
||||
"glob",
|
||||
@@ -869,14 +881,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.16.3"
|
||||
version = "0.15.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87"
|
||||
checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8"
|
||||
dependencies = [
|
||||
"encode_unicode",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"unicode-width 0.2.2",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1034,7 +1047,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"scratch",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1048,7 +1061,7 @@ dependencies = [
|
||||
"indexmap",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1066,7 +1079,7 @@ dependencies = [
|
||||
"indexmap",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1090,7 +1103,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1101,7 +1114,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1110,9 +1123,20 @@ version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69"
|
||||
|
||||
[[package]]
|
||||
name = "dbus"
|
||||
version = "0.9.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "190b6255e8ab55a7b568df5a883e9497edc3e4821c06396612048b430e5ad1e9"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"libdbus-sys",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "declare_clippy_lint"
|
||||
version = "0.1.97"
|
||||
version = "0.1.96"
|
||||
|
||||
[[package]]
|
||||
name = "derive-where"
|
||||
@@ -1122,7 +1146,7 @@ checksum = "d08b3a0bcc0d079199cd476b2cae8435016ec11d1c0986c6901c5ac223041534"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1143,7 +1167,7 @@ dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1153,7 +1177,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
|
||||
dependencies = [
|
||||
"derive_builder_core",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1165,7 +1189,7 @@ dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1240,7 +1264,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1380,13 +1404,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.27"
|
||||
version = "0.2.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db"
|
||||
checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"libredox",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1653,13 +1678,10 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.17.0"
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51"
|
||||
dependencies = [
|
||||
"foldhash 0.2.0",
|
||||
]
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
@@ -1931,26 +1953,26 @@ checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.14.0"
|
||||
version = "2.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
|
||||
checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.17.0",
|
||||
"hashbrown 0.16.1",
|
||||
"serde",
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indicatif"
|
||||
version = "0.18.4"
|
||||
version = "0.17.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25470f23803092da7d239834776d653104d551bc4d7eacaf31e6837854b8e9eb"
|
||||
checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235"
|
||||
dependencies = [
|
||||
"console",
|
||||
"number_prefix",
|
||||
"portable-atomic",
|
||||
"unicode-width 0.2.2",
|
||||
"unit-prefix",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
@@ -2061,7 +2083,7 @@ checksum = "980af8b43c3ad5d8d349ace167ec8170839f753a42d233ba19e08afe1850fa69"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2158,6 +2180,16 @@ version = "0.2.183"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
|
||||
|
||||
[[package]]
|
||||
name = "libdbus-sys"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cbe856efeb50e4681f010e9aaa2bf0a644e10139e54cde10fc83a307c23bd9f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libffi"
|
||||
version = "5.1.0"
|
||||
@@ -2348,7 +2380,7 @@ checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2451,7 +2483,7 @@ dependencies = [
|
||||
"capstone",
|
||||
"chrono",
|
||||
"chrono-tz",
|
||||
"colored",
|
||||
"colored 3.0.0",
|
||||
"directories",
|
||||
"genmc-sys",
|
||||
"getrandom 0.3.3",
|
||||
@@ -2493,7 +2525,7 @@ checksum = "4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2625,6 +2657,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "number_prefix"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
||||
|
||||
[[package]]
|
||||
name = "objc2"
|
||||
version = "0.6.3"
|
||||
@@ -2711,13 +2749,14 @@ checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
||||
|
||||
[[package]]
|
||||
name = "opener"
|
||||
version = "0.8.4"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2fa337e0cf13357c13ef1dc108df1333eb192f75fc170bea03fcf1fd404c2ee"
|
||||
checksum = "d0812e5e4df08da354c851a3376fead46db31c2214f849d3de356d774d057681"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"dbus",
|
||||
"normpath",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2867,7 +2906,7 @@ dependencies = [
|
||||
"pest_meta",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2961,9 +3000,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.13.1"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
|
||||
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic-util"
|
||||
@@ -3077,7 +3116,7 @@ checksum = "7347867d0a7e1208d93b46767be83e2b8f978c3dad35f775ac8d8847551d6fe1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3268,7 +3307,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3361,7 +3400,7 @@ checksum = "8100bb34c0a1d0f907143db3149e6b4eea3c33b9ee8b189720168e818303986f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3767,7 +3806,7 @@ dependencies = [
|
||||
"either",
|
||||
"elsa",
|
||||
"ena",
|
||||
"hashbrown 0.17.0",
|
||||
"hashbrown 0.16.1",
|
||||
"indexmap",
|
||||
"jobserver",
|
||||
"libc",
|
||||
@@ -3956,7 +3995,6 @@ dependencies = [
|
||||
"rustc_ast_pretty",
|
||||
"rustc_data_structures",
|
||||
"rustc_error_messages",
|
||||
"rustc_errors",
|
||||
"rustc_hashes",
|
||||
"rustc_hir_id",
|
||||
"rustc_index",
|
||||
@@ -4077,7 +4115,7 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4223,7 +4261,7 @@ dependencies = [
|
||||
"fluent-syntax",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
@@ -4531,6 +4569,7 @@ name = "rustc_query_impl"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"measureme",
|
||||
"rustc_abi",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_hir",
|
||||
@@ -4804,7 +4843,7 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
@@ -4904,7 +4943,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5021,7 +5060,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde_derive_internals",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5107,7 +5146,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5118,7 +5157,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5232,12 +5271,12 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.6.3"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
|
||||
checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5251,6 +5290,35 @@ dependencies = [
|
||||
"color-eyre",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spdx-expression"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d7ac03c67c572d85049d6db815e20a4a19b41b3d5cca732ac582342021ad77"
|
||||
dependencies = [
|
||||
"nom",
|
||||
"serde",
|
||||
"thiserror 1.0.69",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spdx-rs"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "990870190ec8d8c64ba66e4a6746243d6e57d99353991e0e6092334833f429b1"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"log",
|
||||
"nom",
|
||||
"serde",
|
||||
"spdx-expression",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"thiserror 1.0.69",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.1"
|
||||
@@ -5316,6 +5384,36 @@ version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f"
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.24.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
|
||||
dependencies = [
|
||||
"heck 0.4.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.110"
|
||||
@@ -5335,7 +5433,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5442,9 +5540,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thin-vec"
|
||||
version = "0.2.15"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da322882471314edc77fa5232c587bcb87c9df52bfd0d7d4826f8868ead61899"
|
||||
checksum = "144f754d318415ac792f9d69fc87abbbfc043ce2ef041c60f16ad828f638717d"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
@@ -5472,7 +5570,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5483,7 +5581,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5725,7 +5823,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5858,9 +5956,9 @@ checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
|
||||
|
||||
[[package]]
|
||||
name = "ui_test"
|
||||
version = "0.30.4"
|
||||
version = "0.30.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ada249620d81f010b9a1472b63a5077ac7c722dd0f4bacf6528b313d0b8c15d8"
|
||||
checksum = "44eb652e1a8799d4e47f20851370e86247cbc5270ce677ab1e9409a6d45a9649"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.11.5",
|
||||
"anyhow",
|
||||
@@ -5868,7 +5966,7 @@ dependencies = [
|
||||
"cargo-platform 0.1.9",
|
||||
"cargo_metadata 0.18.1",
|
||||
"color-eyre",
|
||||
"colored",
|
||||
"colored 3.0.0",
|
||||
"comma",
|
||||
"crossbeam-channel",
|
||||
"indicatif",
|
||||
@@ -5921,7 +6019,7 @@ checksum = "a1249a628de3ad34b821ecb1001355bca3940bcb2f88558f1a8bd82e977f75b5"
|
||||
dependencies = [
|
||||
"proc-macro-hack",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
"unic-langid-impl",
|
||||
]
|
||||
|
||||
@@ -6008,12 +6106,6 @@ dependencies = [
|
||||
"diff",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unit-prefix"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3"
|
||||
|
||||
[[package]]
|
||||
name = "unstable-book-gen"
|
||||
version = "0.1.0"
|
||||
@@ -6165,7 +6257,7 @@ dependencies = [
|
||||
"bumpalo",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
@@ -6422,7 +6514,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6433,7 +6525,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6510,7 +6602,16 @@ version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.60.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
||||
dependencies = [
|
||||
"windows-targets 0.53.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6528,14 +6629,31 @@ version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
"windows_aarch64_gnullvm 0.52.6",
|
||||
"windows_aarch64_msvc 0.52.6",
|
||||
"windows_i686_gnu 0.52.6",
|
||||
"windows_i686_gnullvm 0.52.6",
|
||||
"windows_i686_msvc 0.52.6",
|
||||
"windows_x86_64_gnu 0.52.6",
|
||||
"windows_x86_64_gnullvm 0.52.6",
|
||||
"windows_x86_64_msvc 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.53.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
|
||||
dependencies = [
|
||||
"windows-link 0.2.1",
|
||||
"windows_aarch64_gnullvm 0.53.1",
|
||||
"windows_aarch64_msvc 0.53.1",
|
||||
"windows_i686_gnu 0.53.1",
|
||||
"windows_i686_gnullvm 0.53.1",
|
||||
"windows_i686_msvc 0.53.1",
|
||||
"windows_x86_64_gnu 0.53.1",
|
||||
"windows_x86_64_gnullvm 0.53.1",
|
||||
"windows_x86_64_msvc 0.53.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6562,48 +6680,96 @@ version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.5.40"
|
||||
@@ -6729,7 +6895,7 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
@@ -6750,7 +6916,7 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6770,7 +6936,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
@@ -6805,7 +6971,7 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
137
RELEASES.md
137
RELEASES.md
@@ -1,140 +1,3 @@
|
||||
Version 1.95.0 (2026-04-16)
|
||||
===========================
|
||||
|
||||
<a id="1.95-Language"></a>
|
||||
|
||||
Language
|
||||
--------
|
||||
- [Stabilize `if let` guards on match arms](https://github.com/rust-lang/rust/pull/141295)
|
||||
- [`irrefutable_let_patterns` lint no longer lints on let chains](https://github.com/rust-lang/rust/pull/146832)
|
||||
- [Support importing path-segment keywords with renaming](https://github.com/rust-lang/rust/pull/146972)
|
||||
- [Stabilize inline assembly for PowerPC and PowerPC64](https://github.com/rust-lang/rust/pull/147996)
|
||||
- [const-eval: be more consistent in the behavior of padding during typed copies](https://github.com/rust-lang/rust/pull/148967)
|
||||
- [Const blocks are no longer evaluated to determine if expressions involving fallible operations can implicitly be constant-promoted.](https://github.com/rust-lang/rust/pull/150557). Expressions whose ability to implicitly be promoted would depend on the result of a const block are no longer implicitly promoted.
|
||||
- [Make operational semantics of pattern matching independent of crate and module](https://github.com/rust-lang/rust/pull/150681)
|
||||
|
||||
|
||||
<a id="1.95-Compiler"></a>
|
||||
|
||||
Compiler
|
||||
--------
|
||||
|
||||
- [Stabilize `--remap-path-scope` for controlling the scoping of how paths get remapped in the resulting binary](https://github.com/rust-lang/rust/pull/147611)
|
||||
- [Apply patches for CVE-2026-6042 and CVE-2026-40200 to vendored musl](https://github.com/rust-lang/rust/pull/155171)
|
||||
|
||||
<a id="1.95-Platform-Support"></a>
|
||||
|
||||
Platform Support
|
||||
----------------
|
||||
- [Promote `powerpc64-unknown-linux-musl` to Tier 2 with host tools](https://github.com/rust-lang/rust/pull/149962)
|
||||
- [Promote `aarch64-apple-tvos` to Tier 2](https://github.com/rust-lang/rust/pull/152021)
|
||||
- [Promote `aarch64-apple-tvos-sim` to Tier 2](https://github.com/rust-lang/rust/pull/152021)
|
||||
- [Promote `aarch64-apple-watchos` to Tier 2](https://github.com/rust-lang/rust/pull/152021)
|
||||
- [Promote `aarch64-apple-watchos-sim` to Tier 2](https://github.com/rust-lang/rust/pull/152021)
|
||||
- [Promote `aarch64-apple-visionos` to Tier 2](https://github.com/rust-lang/rust/pull/152021)
|
||||
- [Promote `aarch64-apple-visionos-sim` to Tier 2](https://github.com/rust-lang/rust/pull/152021)
|
||||
|
||||
|
||||
Refer to Rust's [platform support page][platform-support-doc]
|
||||
for more information on Rust's tiered platform support.
|
||||
|
||||
[platform-support-doc]: https://doc.rust-lang.org/rustc/platform-support.html
|
||||
|
||||
<a id="1.95-Libraries"></a>
|
||||
|
||||
Libraries
|
||||
---------
|
||||
- [`thread::scope`: document how join interacts with TLS destructors](https://github.com/rust-lang/rust/pull/149482)
|
||||
- [Speed up `str::contains` on aarch64 targets with `neon` target feature enabled by default](https://github.com/rust-lang/rust/pull/152176)
|
||||
|
||||
|
||||
<a id="1.95-Stabilized-APIs"></a>
|
||||
|
||||
Stabilized APIs
|
||||
---------------
|
||||
|
||||
- [`MaybeUninit<[T; N]>: From<[MaybeUninit<T>; N]>`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#impl-From%3CMaybeUninit%3C%5BT;+N%5D%3E%3E-for-%5BMaybeUninit%3CT%3E;+N%5D)
|
||||
- [`MaybeUninit<[T; N]>: AsRef<[MaybeUninit<T>; N]>`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#impl-AsRef%3C%5BMaybeUninit%3CT%3E;+N%5D%3E-for-MaybeUninit%3C%5BT;+N%5D%3E)
|
||||
- [`MaybeUninit<[T; N]>: AsRef<[MaybeUninit<T>]>`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#impl-AsRef%3C%5BMaybeUninit%3CT%3E%5D%3E-for-MaybeUninit%3C%5BT;+N%5D%3E)
|
||||
- [`MaybeUninit<[T; N]>: AsMut<[MaybeUninit<T>; N]>`](https://doc.rust-lang.org/beta/std/mem/union.MaybeUninit.html#impl-AsMut%3C%5BMaybeUninit%3CT%3E;+N%5D%3E-for-MaybeUninit%3C%5BT;+N%5D%3E)
|
||||
- [`MaybeUninit<[T; N]>: AsMut<[MaybeUninit<T>]>`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#impl-AsMut%3C%5BMaybeUninit%3CT%3E%5D%3E-for-MaybeUninit%3C%5BT;+N%5D%3E)
|
||||
- [`[MaybeUninit<T>; N]: From<MaybeUninit<[T; N]>>`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#impl-From%3C%5BMaybeUninit%3CT%3E;+N%5D%3E-for-MaybeUninit%3C%5BT;+N%5D%3E)
|
||||
- [`Cell<[T; N]>: AsRef<[Cell<T>; N]>`](https://doc.rust-lang.org/stable/std/cell/struct.Cell.html#impl-AsRef%3C%5BCell%3CT%3E;+N%5D%3E-for-Cell%3C%5BT;+N%5D%3E)
|
||||
- [`Cell<[T; N]>: AsRef<[Cell<T>]>`](https://doc.rust-lang.org/stable/std/cell/struct.Cell.html#impl-AsRef%3C%5BCell%3CT%3E%5D%3E-for-Cell%3C%5BT;+N%5D%3E)
|
||||
- [`Cell<[T]>: AsRef<[Cell<T>]>`](https://doc.rust-lang.org/stable/std/cell/struct.Cell.html#impl-AsRef%3C%5BCell%3CT%3E%5D%3E-for-Cell%3C%5BT%5D%3E)
|
||||
- [`bool: TryFrom<{integer}>`](https://doc.rust-lang.org/stable/std/primitive.bool.html#impl-TryFrom%3Cu128%3E-for-bool)
|
||||
- [`AtomicPtr::update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicPtr.html#method.update)
|
||||
- [`AtomicPtr::try_update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicPtr.html#method.try_update)
|
||||
- [`AtomicBool::update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicBool.html#method.update)
|
||||
- [`AtomicBool::try_update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicBool.html#method.try_update)
|
||||
- [`AtomicIn::update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicIsize.html#method.update)
|
||||
- [`AtomicIn::try_update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicIsize.html#method.try_update)
|
||||
- [`AtomicUn::update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicUsize.html#method.update)
|
||||
- [`AtomicUn::try_update`](https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicUsize.html#method.try_update)
|
||||
- [`cfg_select!`](https://doc.rust-lang.org/stable/std/macro.cfg_select.html)
|
||||
- [`mod core::range`](https://doc.rust-lang.org/stable/core/range/index.html)
|
||||
- [`core::range::RangeInclusive`](https://doc.rust-lang.org/stable/core/range/struct.RangeInclusive.html)
|
||||
- [`core::range::RangeInclusiveIter`](https://doc.rust-lang.org/stable/core/range/struct.RangeInclusiveIter.html)
|
||||
- [`core::hint::cold_path`](https://doc.rust-lang.org/stable/core/hint/fn.cold_path.html)
|
||||
- [`<*const T>::as_ref_unchecked`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.as_ref_unchecked)
|
||||
- [`<*mut T>::as_ref_unchecked`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.as_ref_unchecked-1)
|
||||
- [`<*mut T>::as_mut_unchecked`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.as_mut_unchecked)
|
||||
- [`Vec::push_mut`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.push_mut)
|
||||
- [`Vec::insert_mut`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.insert_mut)
|
||||
- [`VecDeque::push_front_mut`](https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.push_front_mut)
|
||||
- [`VecDeque::push_back_mut`](https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.push_back_mut)
|
||||
- [`VecDeque::insert_mut`](https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.insert_mut)
|
||||
- [`LinkedList::push_front_mut`](https://doc.rust-lang.org/stable/std/collections/struct.LinkedList.html#method.push_front_mut)
|
||||
- [`LinkedList::push_back_mut`](https://doc.rust-lang.org/stable/std/collections/struct.LinkedList.html#method.push_back_mut)
|
||||
- [`Layout::dangling_ptr`](https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.dangling_ptr)
|
||||
- [`Layout::repeat`](https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.repeat)
|
||||
- [`Layout::repeat_packed`](https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.repeat_packed)
|
||||
- [`Layout::extend_packed`](https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.extend_packed)
|
||||
|
||||
These previously stable APIs are now stable in const contexts:
|
||||
|
||||
- [`fmt::from_fn`](https://doc.rust-lang.org/stable/std/fmt/fn.from_fn.html)
|
||||
- [`ControlFlow::is_break`](https://doc.rust-lang.org/stable/core/ops/enum.ControlFlow.html#method.is_break)
|
||||
- [`ControlFlow::is_continue`](https://doc.rust-lang.org/stable/core/ops/enum.ControlFlow.html#method.is_continue)
|
||||
|
||||
<a id="1.95-Rustdoc"></a>
|
||||
|
||||
Rustdoc
|
||||
-----
|
||||
- [In search results, rank unstable items lower](https://github.com/rust-lang/rust/pull/149460)
|
||||
- [Add new "hide deprecated items" setting in rustdoc](https://github.com/rust-lang/rust/pull/151091)
|
||||
|
||||
<a id="1.95-Compatibility-Notes"></a>
|
||||
|
||||
Compatibility Notes
|
||||
-------------------
|
||||
- [Array coercions may now result in less inference constraints than before](https://github.com/rust-lang/rust/pull/140283)
|
||||
- Importing `$crate` without renaming, i.e. `use $crate::{self};`, is now no longer permitted due to stricter error checking for `self` imports.
|
||||
- [const-eval: be more consistent in the behavior of padding during typed copies.](https://github.com/rust-lang/rust/pull/148967)
|
||||
In very rare cases, this may cause compilation errors due to bytes from parts of a pointer ending up in the padding bytes of a `const` or `static`.
|
||||
- [A future-incompatibility warning lint `ambiguous_glob_imported_traits` is now reported when using an ambiguously glob imported trait](https://github.com/rust-lang/rust/pull/149058)
|
||||
- [Check lifetime bounds of types mentioning only type parameters](https://github.com/rust-lang/rust/pull/149389)
|
||||
- [Report more visibility-related ambiguous import errors](https://github.com/rust-lang/rust/pull/149596)
|
||||
- [Deprecate `Eq::assert_receiver_is_total_eq` and emit future compatibility warnings on manual impls](https://github.com/rust-lang/rust/pull/149978)
|
||||
- [powerpc64: Use the ELF ABI version set in target spec instead of guessing](https://github.com/rust-lang/rust/pull/150468) (fixes the ELF ABI used by the OpenBSD target)
|
||||
- Matching on a `#[non_exhaustive]` enum [now reads the discriminant, even if the enum has only one variant](https://github.com/rust-lang/rust/pull/150681). This can cause closures to capture values that they previously wouldn't.
|
||||
- `mut ref` and `mut ref mut` patterns, part of the unstable [Match Ergonomics 2024 RFC](https://github.com/rust-lang/rust/issues/123076), were accidentally allowed on stable within struct pattern field shorthand. These patterns are now correctly feature-gated as unstable in this position.
|
||||
- [Add future-compatibility warning for derive helper attributes which conflict with built-in attributes](https://github.com/rust-lang/rust/pull/151152)
|
||||
- [JSON target specs](https://doc.rust-lang.org/rustc/targets/custom.html) have been destabilized and now require `-Z unstable-options` to use. Previously, they could not be used without the standard library, which has no stable build mechanism. In preparation for the `build-std` project adding that support, JSON target specs are being proactively gated to ensure they remain unstable even if `build-std` is stabilized. Cargo now includes the `-Z json-target-spec` CLI flag to automatically pass `-Z unstable-options` to the compiler when needed. See [#150151](https://github.com/rust-lang/rust/pull/150151), [#151534](https://github.com/rust-lang/rust/pull/150151), and [rust-lang/cargo#16557](https://github.com/rust-lang/cargo/pull/16557).
|
||||
- [The arguments of `#[feature]` attributes on invalid targets are now checked](https://github.com/rust-lang/rust/issues/153764)
|
||||
|
||||
<a id="1.95-Internal-Changes"></a>
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
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.
|
||||
|
||||
- [Update to LLVM 22](https://github.com/rust-lang/rust/pull/150722)
|
||||
|
||||
|
||||
Version 1.94.1 (2026-03-26)
|
||||
===========================
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ impl HomogeneousAggregate {
|
||||
/// Try to combine two `HomogeneousAggregate`s, e.g. from two fields in
|
||||
/// the same `struct`. Only succeeds if only one of them has any data,
|
||||
/// or both units are identical.
|
||||
#[cfg(feature = "nightly")]
|
||||
fn merge(self, other: HomogeneousAggregate) -> Result<HomogeneousAggregate, Heterogeneous> {
|
||||
match (self, other) {
|
||||
(x, HomogeneousAggregate::NoData) | (HomogeneousAggregate::NoData, x) => Ok(x),
|
||||
@@ -76,11 +75,10 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
|
||||
Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size }))
|
||||
}
|
||||
|
||||
BackendRepr::SimdVector { element, count: _ } => {
|
||||
BackendRepr::SimdVector { .. } => {
|
||||
assert!(!self.is_zst());
|
||||
|
||||
Ok(HomogeneousAggregate::Homogeneous(Reg {
|
||||
kind: RegKind::Vector { hint_vector_elem: element.primitive() },
|
||||
kind: RegKind::Vector,
|
||||
size: self.size,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -1,19 +1,14 @@
|
||||
#[cfg(feature = "nightly")]
|
||||
use rustc_macros::HashStable_Generic;
|
||||
|
||||
use crate::{Align, HasDataLayout, Integer, Primitive, Size};
|
||||
use crate::{Align, HasDataLayout, Size};
|
||||
|
||||
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum RegKind {
|
||||
Integer,
|
||||
Float,
|
||||
Vector {
|
||||
/// The `hint_vector_elem` is strictly for optimization purposes. E.g. it can be used by
|
||||
/// a codegen backend to prevent extra bitcasts that obscure a pattern. Alternatively,
|
||||
/// it can be safely ignored by always picking i8.
|
||||
hint_vector_elem: Primitive,
|
||||
},
|
||||
Vector,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
|
||||
@@ -41,12 +36,6 @@ impl Reg {
|
||||
reg_ctor!(f32, Float, 32);
|
||||
reg_ctor!(f64, Float, 64);
|
||||
reg_ctor!(f128, Float, 128);
|
||||
|
||||
/// A vector of the given size with an unknown (and irrelevant) element type.
|
||||
pub fn opaque_vector(size: Size) -> Reg {
|
||||
// Default to an i8 vector of the given size.
|
||||
Reg { kind: RegKind::Vector { hint_vector_elem: Primitive::Int(Integer::I8, true) }, size }
|
||||
}
|
||||
}
|
||||
|
||||
impl Reg {
|
||||
@@ -69,7 +58,7 @@ impl Reg {
|
||||
128 => dl.f128_align,
|
||||
_ => panic!("unsupported float: {self:?}"),
|
||||
},
|
||||
RegKind::Vector { .. } => dl.llvmlike_vector_align(self.size),
|
||||
RegKind::Vector => dl.llvmlike_vector_align(self.size),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,29 +131,6 @@ macro_rules! abi_impls {
|
||||
$($e_name::$variant $( { unwind: $uw } )* => $tok,)*
|
||||
}
|
||||
}
|
||||
// FIXME(FnSigKind): when PartialEq is stably const, use it instead
|
||||
const fn internal_const_eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
$( ( $e_name::$variant $( { unwind: $uw } )* , $e_name::$variant $( { unwind: $uw } )* ) => true,)*
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
// ALL_VARIANTS.iter().position(|v| v == self), but const
|
||||
pub const fn as_packed(&self) -> u8 {
|
||||
let mut index = 0;
|
||||
while index < $e_name::ALL_VARIANTS.len() {
|
||||
if self.internal_const_eq(&$e_name::ALL_VARIANTS[index]) {
|
||||
return index as u8;
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
panic!("unreachable: invalid ExternAbi variant");
|
||||
}
|
||||
pub const fn from_packed(index: u8) -> Self {
|
||||
let index = index as usize;
|
||||
assert!(index < $e_name::ALL_VARIANTS.len(), "invalid ExternAbi index");
|
||||
$e_name::ALL_VARIANTS[index]
|
||||
}
|
||||
}
|
||||
|
||||
impl ::core::str::FromStr for $e_name {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// tidy-alphabetical-start
|
||||
#![cfg_attr(bootstrap, feature(assert_matches))]
|
||||
#![cfg_attr(feature = "nightly", allow(internal_features))]
|
||||
#![cfg_attr(feature = "nightly", feature(rustc_attrs))]
|
||||
#![cfg_attr(feature = "nightly", feature(step_trait))]
|
||||
@@ -47,15 +48,11 @@ use bitflags::bitflags;
|
||||
#[cfg(feature = "nightly")]
|
||||
use rustc_data_structures::stable_hasher::StableOrd;
|
||||
#[cfg(feature = "nightly")]
|
||||
use rustc_error_messages::{DiagArgValue, IntoDiagArg};
|
||||
#[cfg(feature = "nightly")]
|
||||
use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, msg};
|
||||
use rustc_hashes::Hash64;
|
||||
use rustc_index::{Idx, IndexSlice, IndexVec};
|
||||
#[cfg(feature = "nightly")]
|
||||
use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_Generic};
|
||||
#[cfg(feature = "nightly")]
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
mod callconv;
|
||||
mod canon_abi;
|
||||
@@ -774,14 +771,6 @@ impl Endian {
|
||||
Self::Big => "big",
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
pub fn desc_symbol(&self) -> Symbol {
|
||||
match self {
|
||||
Self::Little => sym::little,
|
||||
Self::Big => sym::big,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Endian {
|
||||
@@ -1753,9 +1742,6 @@ pub struct AddressSpace(pub u32);
|
||||
impl AddressSpace {
|
||||
/// LLVM's `0` address space.
|
||||
pub const ZERO: Self = AddressSpace(0);
|
||||
/// The address space for workgroup memory on nvptx and amdgpu.
|
||||
/// See e.g. the `gpu_launch_sized_workgroup_mem` intrinsic for details.
|
||||
pub const GPU_WORKGROUP: Self = AddressSpace(3);
|
||||
}
|
||||
|
||||
/// How many scalable vectors are in a `BackendRepr::ScalableVector`?
|
||||
@@ -1780,24 +1766,6 @@ impl NumScalableVectors {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
impl IntoDiagArg for NumScalableVectors {
|
||||
fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
|
||||
DiagArgValue::Str(std::borrow::Cow::Borrowed(match self.0 {
|
||||
0 => panic!("`NumScalableVectors(0)` is illformed"),
|
||||
1 => "one",
|
||||
2 => "two",
|
||||
3 => "three",
|
||||
4 => "four",
|
||||
5 => "five",
|
||||
6 => "six",
|
||||
7 => "seven",
|
||||
8 => "eight",
|
||||
_ => panic!("`NumScalableVectors(N)` for N>8 is illformed"),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
/// The way we represent values to the backend
|
||||
///
|
||||
/// Previously this was conflated with the "ABI" a type is given, as in the platform-specific ABI.
|
||||
@@ -2054,7 +2022,8 @@ impl Niche {
|
||||
assert!(size.bits() <= 128);
|
||||
let max_value = size.unsigned_int_max();
|
||||
|
||||
let available = v.start.wrapping_sub(v.end).wrapping_sub(1) & max_value;
|
||||
let niche = v.end.wrapping_add(1)..v.start;
|
||||
let available = niche.end.wrapping_sub(niche.start) & max_value;
|
||||
if count > available {
|
||||
return None;
|
||||
}
|
||||
@@ -2082,17 +2051,7 @@ impl Niche {
|
||||
Some((start, Scalar::Initialized { value, valid_range: v.with_end(end) }))
|
||||
};
|
||||
let distance_end_zero = max_value - v.end;
|
||||
// FIXME: this ought to work for `bool` too, but that seems to be hitting a miscompilation
|
||||
// <https://github.com/rust-lang/rust/pull/155473#issuecomment-4302036343>
|
||||
if count == 1 && v != (WrappingRange { start: 0, end: 1 }) {
|
||||
// We only need one, so just pick the one closest to zero.
|
||||
// Not only does that obviously use zero if it's possible, but it also
|
||||
// simplifies testing things like `Option<char>`, since looking for `-1`
|
||||
// is easier than looking for `1114112` (and matches clang's `WEOF`).
|
||||
let next_up = size.sign_extend(v.end.wrapping_add(1)).unsigned_abs();
|
||||
let next_down = size.sign_extend(v.start.wrapping_sub(1)).unsigned_abs();
|
||||
if next_down <= next_up { move_start(v) } else { move_end(v) }
|
||||
} else if v.start > v.end {
|
||||
if v.start > v.end {
|
||||
// zero is unavailable because wrapping occurs
|
||||
move_end(v)
|
||||
} else if v.start <= distance_end_zero {
|
||||
|
||||
@@ -140,19 +140,25 @@ impl<T> TypedArena<T> {
|
||||
/// Allocates an object in the `TypedArena`, returning a reference to it.
|
||||
#[inline]
|
||||
pub fn alloc(&self, object: T) -> &mut T {
|
||||
assert!(size_of::<T>() != 0);
|
||||
|
||||
if self.ptr == self.end {
|
||||
self.grow(1)
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let ptr = self.ptr.get();
|
||||
// Advance the pointer.
|
||||
self.ptr.set(self.ptr.get().add(1));
|
||||
// Write into uninitialized memory.
|
||||
ptr::write(ptr, object);
|
||||
&mut *ptr
|
||||
if size_of::<T>() == 0 {
|
||||
self.ptr.set(self.ptr.get().wrapping_byte_add(1));
|
||||
let ptr = ptr::NonNull::<T>::dangling().as_ptr();
|
||||
// Don't drop the object. This `write` is equivalent to `forget`.
|
||||
ptr::write(ptr, object);
|
||||
&mut *ptr
|
||||
} else {
|
||||
let ptr = self.ptr.get();
|
||||
// Advance the pointer.
|
||||
self.ptr.set(self.ptr.get().add(1));
|
||||
// Write into uninitialized memory.
|
||||
ptr::write(ptr, object);
|
||||
&mut *ptr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,9 +287,10 @@ impl<T> TypedArena<T> {
|
||||
// Also ensure that this chunk can fit `additional`.
|
||||
new_cap = cmp::max(additional, new_cap);
|
||||
|
||||
let chunk = chunks.push_mut(ArenaChunk::<T>::new(new_cap));
|
||||
let mut chunk = ArenaChunk::<T>::new(new_cap);
|
||||
self.ptr.set(chunk.start());
|
||||
self.end.set(chunk.end());
|
||||
chunks.push(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,10 +303,16 @@ impl<T> TypedArena<T> {
|
||||
let end = self.ptr.get().addr();
|
||||
// We then calculate the number of elements to be dropped in the last chunk,
|
||||
// which is the filled area's length.
|
||||
assert_ne!(size_of::<T>(), 0);
|
||||
// FIXME: this should *likely* use `offset_from`, but more
|
||||
// investigation is needed (including running tests in miri).
|
||||
let diff = (end - start) / size_of::<T>();
|
||||
let diff = if size_of::<T>() == 0 {
|
||||
// `T` is ZST. It can't have a drop flag, so the value here doesn't matter. We get
|
||||
// the number of zero-sized values in the last and only chunk, just out of caution.
|
||||
// Recall that `end` was incremented for each allocated value.
|
||||
end - start
|
||||
} else {
|
||||
// FIXME: this should *likely* use `offset_from`, but more
|
||||
// investigation is needed (including running tests in miri).
|
||||
(end - start) / size_of::<T>()
|
||||
};
|
||||
// Pass that to the `destroy` method.
|
||||
unsafe {
|
||||
last_chunk.destroy(diff);
|
||||
@@ -406,7 +419,7 @@ impl DroplessArena {
|
||||
// Also ensure that this chunk can fit `additional`.
|
||||
new_cap = cmp::max(additional, new_cap);
|
||||
|
||||
let chunk = chunks.push_mut(ArenaChunk::new(align_up(new_cap, PAGE)));
|
||||
let mut chunk = ArenaChunk::new(align_up(new_cap, PAGE));
|
||||
self.start.set(chunk.start());
|
||||
|
||||
// Align the end to DROPLESS_ALIGNMENT.
|
||||
@@ -417,6 +430,8 @@ impl DroplessArena {
|
||||
debug_assert!(chunk.start().addr() <= end);
|
||||
|
||||
self.end.set(chunk.end().with_addr(end));
|
||||
|
||||
chunks.push(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ impl<T> TypedArena<T> {
|
||||
if let Some(last_chunk) = chunks_borrow.last_mut() {
|
||||
self.clear_last_chunk(last_chunk);
|
||||
let len = chunks_borrow.len();
|
||||
// If `T` is ZST, code below has no effect.
|
||||
for mut chunk in chunks_borrow.drain(..len - 1) {
|
||||
chunk.destroy(chunk.entries);
|
||||
}
|
||||
@@ -116,6 +117,18 @@ fn test_noncopy() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_typed_arena_zero_sized() {
|
||||
let arena = TypedArena::default();
|
||||
#[cfg(not(miri))]
|
||||
const N: usize = 100000;
|
||||
#[cfg(miri)]
|
||||
const N: usize = 1000;
|
||||
for _ in 0..N {
|
||||
arena.alloc(());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_typed_arena_clear() {
|
||||
let mut arena = TypedArena::default();
|
||||
@@ -194,8 +207,7 @@ thread_local! {
|
||||
static DROP_COUNTER: Cell<u32> = Cell::new(0)
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
struct SmallDroppable(u8);
|
||||
struct SmallDroppable;
|
||||
|
||||
impl Drop for SmallDroppable {
|
||||
fn drop(&mut self) {
|
||||
@@ -210,7 +222,7 @@ fn test_typed_arena_drop_small_count() {
|
||||
let arena: TypedArena<SmallDroppable> = TypedArena::default();
|
||||
for _ in 0..100 {
|
||||
// Allocate something with drop glue to make sure it doesn't leak.
|
||||
arena.alloc(SmallDroppable(0));
|
||||
arena.alloc(SmallDroppable);
|
||||
}
|
||||
// dropping
|
||||
};
|
||||
|
||||
@@ -15,6 +15,6 @@ rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_serialize = { path = "../rustc_serialize" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
||||
thin-vec = "0.2.15"
|
||||
thin-vec = "0.2.12"
|
||||
tracing = "0.1"
|
||||
# tidy-alphabetical-end
|
||||
|
||||
@@ -3786,10 +3786,10 @@ pub struct TraitAlias {
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
||||
pub struct Trait {
|
||||
pub impl_restriction: ImplRestriction,
|
||||
pub constness: Const,
|
||||
pub safety: Safety,
|
||||
pub is_auto: IsAuto,
|
||||
pub impl_restriction: ImplRestriction,
|
||||
pub ident: Ident,
|
||||
pub generics: Generics,
|
||||
#[visitable(extra = BoundKind::SuperTraits)]
|
||||
@@ -3901,17 +3901,12 @@ pub struct Delegation {
|
||||
pub from_glob: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
||||
pub enum DelegationSuffixes {
|
||||
List(ThinVec<(Ident, Option<Ident>)>),
|
||||
Glob(Span),
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
||||
pub struct DelegationMac {
|
||||
pub qself: Option<Box<QSelf>>,
|
||||
pub prefix: Path,
|
||||
pub suffixes: DelegationSuffixes,
|
||||
// Some for list delegation, and None for glob delegation.
|
||||
pub suffixes: Option<ThinVec<(Ident, Option<Ident>)>>,
|
||||
pub body: Option<Box<Block>>,
|
||||
}
|
||||
|
||||
@@ -3923,13 +3918,6 @@ pub struct StaticItem {
|
||||
pub mutability: Mutability,
|
||||
pub expr: Option<Box<Expr>>,
|
||||
pub define_opaque: Option<ThinVec<(NodeId, Path)>>,
|
||||
|
||||
/// This static is an implementation of an externally implementable item (EII).
|
||||
/// This means, there was an EII declared somewhere and this static is the
|
||||
/// implementation that should be used for the declaration.
|
||||
///
|
||||
/// For statics, there may be at most one `EiiImpl`, but this is a `ThinVec` to make usages of this field nicer.
|
||||
pub eii_impls: ThinVec<EiiImpl>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
||||
|
||||
@@ -235,6 +235,34 @@ impl AttributeExt for Attribute {
|
||||
}
|
||||
}
|
||||
|
||||
fn deprecation_note(&self) -> Option<Ident> {
|
||||
match &self.kind {
|
||||
AttrKind::Normal(normal) if normal.item.path == sym::deprecated => {
|
||||
let meta = &normal.item;
|
||||
|
||||
// #[deprecated = "..."]
|
||||
if let Some(s) = meta.value_str() {
|
||||
return Some(Ident { name: s, span: meta.span() });
|
||||
}
|
||||
|
||||
// #[deprecated(note = "...")]
|
||||
if let Some(list) = meta.meta_item_list() {
|
||||
for nested in list {
|
||||
if let Some(mi) = nested.meta_item()
|
||||
&& mi.path == sym::note
|
||||
&& let Some(s) = mi.value_str()
|
||||
{
|
||||
return Some(Ident { name: s, span: mi.span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn doc_resolution_scope(&self) -> Option<AttrStyle> {
|
||||
match &self.kind {
|
||||
AttrKind::DocComment(..) => Some(self.style),
|
||||
@@ -313,34 +341,6 @@ impl Attribute {
|
||||
)],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deprecation_note(&self) -> Option<Ident> {
|
||||
match &self.kind {
|
||||
AttrKind::Normal(normal) if normal.item.path == sym::deprecated => {
|
||||
let meta = &normal.item;
|
||||
|
||||
// #[deprecated = "..."]
|
||||
if let Some(s) = meta.value_str() {
|
||||
return Some(Ident { name: s, span: meta.span() });
|
||||
}
|
||||
|
||||
// #[deprecated(note = "...")]
|
||||
if let Some(list) = meta.meta_item_list() {
|
||||
for nested in list {
|
||||
if let Some(mi) = nested.meta_item()
|
||||
&& mi.path == sym::note
|
||||
&& let Some(s) = mi.value_str()
|
||||
{
|
||||
return Some(Ident { name: s, span: mi.span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AttrItem {
|
||||
@@ -824,19 +824,19 @@ pub fn mk_attr_name_value_str(
|
||||
mk_attr(g, style, unsafety, path, args, span)
|
||||
}
|
||||
|
||||
pub fn filter_by_name(attrs: &[Attribute], name: Symbol) -> impl Iterator<Item = &Attribute> {
|
||||
pub fn filter_by_name<A: AttributeExt>(attrs: &[A], name: Symbol) -> impl Iterator<Item = &A> {
|
||||
attrs.iter().filter(move |attr| attr.has_name(name))
|
||||
}
|
||||
|
||||
pub fn find_by_name(attrs: &[Attribute], name: Symbol) -> Option<&Attribute> {
|
||||
pub fn find_by_name<A: AttributeExt>(attrs: &[A], name: Symbol) -> Option<&A> {
|
||||
filter_by_name(attrs, name).next()
|
||||
}
|
||||
|
||||
pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: Symbol) -> Option<Symbol> {
|
||||
pub fn first_attr_value_str_by_name(attrs: &[impl AttributeExt], name: Symbol) -> Option<Symbol> {
|
||||
find_by_name(attrs, name).and_then(|attr| attr.value_str())
|
||||
}
|
||||
|
||||
pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool {
|
||||
pub fn contains_name(attrs: &[impl AttributeExt], name: Symbol) -> bool {
|
||||
find_by_name(attrs, name).is_some()
|
||||
}
|
||||
|
||||
@@ -911,6 +911,11 @@ pub trait AttributeExt: Debug {
|
||||
/// * `#[doc(...)]` returns `None`.
|
||||
fn doc_str(&self) -> Option<Symbol>;
|
||||
|
||||
/// Returns the deprecation note if this is deprecation attribute.
|
||||
/// * `#[deprecated = "note"]` returns `Some("note")`.
|
||||
/// * `#[deprecated(note = "note", ...)]` returns `Some("note")`.
|
||||
fn deprecation_note(&self) -> Option<Ident>;
|
||||
|
||||
/// Returns whether this attribute is any of the proc macro attributes.
|
||||
/// i.e. `proc_macro`, `proc_macro_attribute` or `proc_macro_derive`.
|
||||
fn is_proc_macro_attr(&self) -> bool {
|
||||
|
||||
@@ -430,7 +430,6 @@ macro_rules! common_visitor_and_walkers {
|
||||
Defaultness,
|
||||
Delegation,
|
||||
DelegationMac,
|
||||
DelegationSuffixes,
|
||||
DelimArgs,
|
||||
DelimSpan,
|
||||
EnumDef,
|
||||
|
||||
@@ -23,6 +23,6 @@ rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
||||
thin-vec = "0.2.15"
|
||||
thin-vec = "0.2.12"
|
||||
tracing = "0.1"
|
||||
# tidy-alphabetical-end
|
||||
|
||||
@@ -18,9 +18,11 @@ use super::errors::{
|
||||
InvalidRegisterClass, RegisterClassOnlyClobber, RegisterClassOnlyClobberStable,
|
||||
RegisterConflict,
|
||||
};
|
||||
use crate::{AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, ParamMode};
|
||||
use crate::{
|
||||
AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, ParamMode, ResolverAstLoweringExt,
|
||||
};
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
pub(crate) fn lower_inline_asm(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
@@ -201,6 +203,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
},
|
||||
InlineAsmOperand::Sym { sym } => {
|
||||
let static_def_id = self
|
||||
.resolver
|
||||
.get_partial_res(sym.id)
|
||||
.and_then(|res| res.full_res())
|
||||
.and_then(|res| match res {
|
||||
|
||||
@@ -4,9 +4,9 @@ use rustc_hir::Target;
|
||||
use rustc_span::sym;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext};
|
||||
use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext, ResolverAstLoweringExt};
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
pub(super) fn lower_block(
|
||||
&mut self,
|
||||
b: &Block,
|
||||
|
||||
@@ -2,9 +2,9 @@ use std::sync::Arc;
|
||||
|
||||
use thin_vec::thin_vec;
|
||||
|
||||
use crate::LoweringContext;
|
||||
use crate::{LoweringContext, ResolverAstLoweringExt};
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
/// Lowered contracts are guarded with the `contract_checks` compiler flag,
|
||||
/// i.e. the flag turns into a boolean guard in the lowered HIR. The reason
|
||||
/// for not eliminating the contract code entirely when the `contract_checks`
|
||||
|
||||
@@ -39,16 +39,16 @@
|
||||
use std::iter;
|
||||
|
||||
use ast::visit::Visitor;
|
||||
use hir::def::{DefKind, Res};
|
||||
use hir::def::{DefKind, PartialRes, Res};
|
||||
use hir::{BodyId, HirId};
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::*;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::attrs::{AttributeKind, InlineAttr};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{self as hir, FnDeclFlags};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::Asyncness;
|
||||
use rustc_span::symbol::kw;
|
||||
@@ -105,7 +105,7 @@ static ATTRS_ADDITIONS: &[AttrAdditionInfo] = &[
|
||||
},
|
||||
];
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
fn is_method(&self, def_id: DefId, span: Span) -> bool {
|
||||
match self.tcx.def_kind(def_id) {
|
||||
DefKind::Fn => false,
|
||||
@@ -143,8 +143,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
let (param_count, c_variadic) = self.param_count(sig_id);
|
||||
|
||||
let mut generics =
|
||||
self.uplift_delegation_generics(delegation, sig_id, item_id, is_method);
|
||||
let mut generics = self.uplift_delegation_generics(delegation, sig_id, item_id);
|
||||
|
||||
let body_id = self.lower_delegation_body(
|
||||
delegation,
|
||||
@@ -266,13 +265,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
|
||||
fn get_resolution_id(&self, node_id: NodeId) -> Option<DefId> {
|
||||
self.get_partial_res(node_id).and_then(|r| r.expect_full_res().opt_def_id())
|
||||
self.resolver.get_partial_res(node_id).and_then(|r| r.expect_full_res().opt_def_id())
|
||||
}
|
||||
|
||||
// Function parameter count, including C variadic `...` if present.
|
||||
fn param_count(&self, def_id: DefId) -> (usize, bool /*c_variadic*/) {
|
||||
let sig = self.tcx.fn_sig(def_id).skip_binder().skip_binder();
|
||||
(sig.inputs().len() + usize::from(sig.c_variadic()), sig.c_variadic())
|
||||
(sig.inputs().len() + usize::from(sig.c_variadic), sig.c_variadic)
|
||||
}
|
||||
|
||||
fn lower_delegation_decl(
|
||||
@@ -302,8 +301,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
hir::InferDelegationSig::Output(self.arena.alloc(hir::DelegationGenerics {
|
||||
child_args_segment_id: generics.child.args_segment_id,
|
||||
parent_args_segment_id: generics.parent.args_segment_id,
|
||||
self_ty_id: generics.self_ty_id,
|
||||
propagate_self_ty: generics.propagate_self_ty,
|
||||
})),
|
||||
)),
|
||||
span,
|
||||
@@ -312,9 +309,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
self.arena.alloc(hir::FnDecl {
|
||||
inputs,
|
||||
output: hir::FnRetTy::Return(output),
|
||||
fn_decl_kind: FnDeclFlags::default()
|
||||
.set_lifetime_elision_allowed(true)
|
||||
.set_c_variadic(c_variadic),
|
||||
c_variadic,
|
||||
lifetime_elision_allowed: true,
|
||||
implicit_self: hir::ImplicitSelfKind::None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -334,11 +331,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
safety: if self.tcx.codegen_fn_attrs(sig_id).safe_target_features {
|
||||
hir::HeaderSafety::SafeTargetFeatures
|
||||
} else {
|
||||
hir::HeaderSafety::Normal(sig.safety())
|
||||
hir::HeaderSafety::Normal(sig.safety)
|
||||
},
|
||||
constness: self.tcx.constness(sig_id),
|
||||
asyncness,
|
||||
abi: sig.abi(),
|
||||
abi: sig.abi,
|
||||
};
|
||||
|
||||
hir::FnSig { decl, header, span }
|
||||
@@ -417,7 +414,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
&& idx == 0
|
||||
{
|
||||
let mut self_resolver = SelfResolver {
|
||||
ctxt: this,
|
||||
resolver: this.resolver,
|
||||
path_id: delegation.id,
|
||||
self_param_id: pat_node_id,
|
||||
};
|
||||
@@ -436,6 +433,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// also nested delegations may need to access information about this code (#154332),
|
||||
// so it is better to leave this code as opposed to bodies of extern functions,
|
||||
// which are completely erased from existence.
|
||||
// FIXME(fn_delegation): fix `help` in error message (see `inner-attr.stderr`)
|
||||
if param_count == 0
|
||||
&& let Some(block) = block
|
||||
{
|
||||
@@ -508,7 +506,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
// FIXME(fn_delegation): proper support for parent generics propagation
|
||||
// in method call scenario.
|
||||
let segment = self.process_segment(span, &segment, &mut generics.child);
|
||||
let segment = self.process_segment(span, &segment, &mut generics.child, false);
|
||||
let segment = self.arena.alloc(segment);
|
||||
|
||||
self.arena.alloc(hir::Expr {
|
||||
@@ -534,10 +532,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
new_path.segments = self.arena.alloc_from_iter(
|
||||
new_path.segments.iter().enumerate().map(|(idx, segment)| {
|
||||
let mut process_segment = |result, add_lifetimes| {
|
||||
self.process_segment(span, segment, result, add_lifetimes)
|
||||
};
|
||||
|
||||
if idx + 2 == len {
|
||||
self.process_segment(span, segment, &mut generics.parent)
|
||||
process_segment(&mut generics.parent, true)
|
||||
} else if idx + 1 == len {
|
||||
self.process_segment(span, segment, &mut generics.child)
|
||||
process_segment(&mut generics.child, false)
|
||||
} else {
|
||||
segment.clone()
|
||||
}
|
||||
@@ -547,18 +549,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
hir::QPath::Resolved(ty, self.arena.alloc(new_path))
|
||||
}
|
||||
hir::QPath::TypeRelative(ty, segment) => {
|
||||
let segment = self.process_segment(span, segment, &mut generics.child);
|
||||
let segment = self.process_segment(span, segment, &mut generics.child, false);
|
||||
|
||||
hir::QPath::TypeRelative(ty, self.arena.alloc(segment))
|
||||
}
|
||||
};
|
||||
|
||||
generics.self_ty_id = match new_path {
|
||||
hir::QPath::Resolved(ty, _) => ty,
|
||||
hir::QPath::TypeRelative(ty, _) => Some(ty),
|
||||
}
|
||||
.map(|ty| ty.hir_id);
|
||||
|
||||
let callee_path = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(new_path), span));
|
||||
self.arena.alloc(self.mk_expr(hir::ExprKind::Call(callee_path, args), span))
|
||||
};
|
||||
@@ -580,12 +576,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
span: Span,
|
||||
segment: &hir::PathSegment<'hir>,
|
||||
result: &mut GenericsGenerationResult<'hir>,
|
||||
add_lifetimes: bool,
|
||||
) -> hir::PathSegment<'hir> {
|
||||
let details = result.generics.args_propagation_details();
|
||||
|
||||
let segment = if details.should_propagate {
|
||||
let generics = result.generics.into_hir_generics(self, span);
|
||||
let args = generics.into_generic_args(self, span);
|
||||
let args = generics.into_generic_args(self, add_lifetimes, span);
|
||||
|
||||
// Needed for better error messages (`trait-impl-wrong-args-count.rs` test).
|
||||
let args = if args.is_empty() { None } else { Some(args) };
|
||||
@@ -607,7 +604,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
span: Span,
|
||||
delegation: &Delegation,
|
||||
) -> DelegationResults<'hir> {
|
||||
let decl = self.arena.alloc(hir::FnDecl::dummy(span));
|
||||
let decl = self.arena.alloc(hir::FnDecl {
|
||||
inputs: &[],
|
||||
output: hir::FnRetTy::DefaultReturn(span),
|
||||
c_variadic: false,
|
||||
lifetime_elision_allowed: true,
|
||||
implicit_self: hir::ImplicitSelfKind::None,
|
||||
});
|
||||
|
||||
let header = self.generate_header_error();
|
||||
let sig = hir::FnSig { decl, header, span };
|
||||
@@ -665,24 +668,25 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
struct SelfResolver<'a, 'b, 'hir> {
|
||||
ctxt: &'a mut LoweringContext<'b, 'hir>,
|
||||
struct SelfResolver<'a, R> {
|
||||
resolver: &'a mut R,
|
||||
path_id: NodeId,
|
||||
self_param_id: NodeId,
|
||||
}
|
||||
|
||||
impl SelfResolver<'_, '_, '_> {
|
||||
impl<'tcx, R: ResolverAstLoweringExt<'tcx>> SelfResolver<'_, R> {
|
||||
fn try_replace_id(&mut self, id: NodeId) {
|
||||
if let Some(res) = self.ctxt.get_partial_res(id)
|
||||
if let Some(res) = self.resolver.get_partial_res(id)
|
||||
&& let Some(Res::Local(sig_id)) = res.full_res()
|
||||
&& sig_id == self.path_id
|
||||
{
|
||||
self.ctxt.partial_res_overrides.insert(id, self.self_param_id);
|
||||
let new_res = PartialRes::new(Res::Local(self.self_param_id));
|
||||
self.resolver.insert_partial_res(id, new_res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> Visitor<'ast> for SelfResolver<'_, '_, '_> {
|
||||
impl<'ast, 'tcx, R: ResolverAstLoweringExt<'tcx>> Visitor<'ast> for SelfResolver<'_, R> {
|
||||
fn visit_id(&mut self, id: NodeId) {
|
||||
self.try_replace_id(id);
|
||||
}
|
||||
|
||||
@@ -6,57 +6,22 @@ use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::ty::GenericParamDefKind;
|
||||
use rustc_middle::{bug, ty};
|
||||
use rustc_span::symbol::kw;
|
||||
use rustc_span::{Ident, Span, sym};
|
||||
use rustc_span::{Ident, Span};
|
||||
|
||||
use crate::LoweringContext;
|
||||
use crate::{LoweringContext, ResolverAstLoweringExt};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub(super) enum DelegationGenericsKind {
|
||||
pub(super) enum DelegationGenerics<T> {
|
||||
/// User-specified args are present: `reuse foo::<String>;`.
|
||||
UserSpecified,
|
||||
/// The default case when no user-specified args are present: `reuse Trait::foo;`.
|
||||
Default,
|
||||
Default(T),
|
||||
/// In free-to-trait reuse, when user specified args for trait `reuse Trait::<i32>::foo;`
|
||||
/// in this case we need to both generate `Self` and process user args.
|
||||
SelfAndUserSpecified,
|
||||
SelfAndUserSpecified(T),
|
||||
/// In delegations from trait impl to other entities like free functions or trait functions,
|
||||
/// we want to generate a function whose generics matches generics of signature function
|
||||
/// in trait.
|
||||
TraitImpl(bool /* Has user-specified args */),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(super) enum GenericsPosition {
|
||||
Parent,
|
||||
Child,
|
||||
}
|
||||
|
||||
pub(super) struct DelegationGenerics<T> {
|
||||
generics: T,
|
||||
kind: DelegationGenericsKind,
|
||||
pos: GenericsPosition,
|
||||
}
|
||||
|
||||
impl<'hir> DelegationGenerics<&'hir [ty::GenericParamDef]> {
|
||||
fn default(generics: &'hir [ty::GenericParamDef], pos: GenericsPosition) -> Self {
|
||||
DelegationGenerics { generics, pos, kind: DelegationGenericsKind::Default }
|
||||
}
|
||||
|
||||
fn user_specified(generics: &'hir [ty::GenericParamDef], pos: GenericsPosition) -> Self {
|
||||
DelegationGenerics { generics, pos, kind: DelegationGenericsKind::UserSpecified }
|
||||
}
|
||||
|
||||
fn trait_impl(
|
||||
generics: &'hir [ty::GenericParamDef],
|
||||
user_specified: bool,
|
||||
pos: GenericsPosition,
|
||||
) -> Self {
|
||||
DelegationGenerics {
|
||||
generics,
|
||||
pos,
|
||||
kind: DelegationGenericsKind::TraitImpl(user_specified),
|
||||
}
|
||||
}
|
||||
TraitImpl(T, bool /* Has user-specified args */),
|
||||
}
|
||||
|
||||
/// Used for storing either ty generics or their uplifted HIR version. First we obtain
|
||||
@@ -82,8 +47,6 @@ pub(super) struct GenericsGenerationResult<'hir> {
|
||||
pub(super) struct GenericsGenerationResults<'hir> {
|
||||
pub(super) parent: GenericsGenerationResult<'hir>,
|
||||
pub(super) child: GenericsGenerationResult<'hir>,
|
||||
pub(super) self_ty_id: Option<HirId>,
|
||||
pub(super) propagate_self_ty: bool,
|
||||
}
|
||||
|
||||
pub(super) struct GenericArgsPropagationDetails {
|
||||
@@ -91,19 +54,20 @@ pub(super) struct GenericArgsPropagationDetails {
|
||||
pub(super) use_args_in_sig_inheritance: bool,
|
||||
}
|
||||
|
||||
impl DelegationGenericsKind {
|
||||
fn args_propagation_details(self) -> GenericArgsPropagationDetails {
|
||||
impl<T> DelegationGenerics<T> {
|
||||
fn args_propagation_details(&self) -> GenericArgsPropagationDetails {
|
||||
match self {
|
||||
DelegationGenericsKind::UserSpecified
|
||||
| DelegationGenericsKind::SelfAndUserSpecified => GenericArgsPropagationDetails {
|
||||
should_propagate: false,
|
||||
use_args_in_sig_inheritance: true,
|
||||
},
|
||||
DelegationGenericsKind::TraitImpl(user_specified) => GenericArgsPropagationDetails {
|
||||
should_propagate: !user_specified,
|
||||
DelegationGenerics::UserSpecified | DelegationGenerics::SelfAndUserSpecified { .. } => {
|
||||
GenericArgsPropagationDetails {
|
||||
should_propagate: false,
|
||||
use_args_in_sig_inheritance: true,
|
||||
}
|
||||
}
|
||||
DelegationGenerics::TraitImpl(_, user_specified) => GenericArgsPropagationDetails {
|
||||
should_propagate: !*user_specified,
|
||||
use_args_in_sig_inheritance: false,
|
||||
},
|
||||
DelegationGenericsKind::Default => GenericArgsPropagationDetails {
|
||||
DelegationGenerics::Default(_) => GenericArgsPropagationDetails {
|
||||
should_propagate: true,
|
||||
use_args_in_sig_inheritance: false,
|
||||
},
|
||||
@@ -114,18 +78,28 @@ impl DelegationGenericsKind {
|
||||
impl<'hir> HirOrTyGenerics<'hir> {
|
||||
pub(super) fn into_hir_generics(
|
||||
&mut self,
|
||||
ctx: &mut LoweringContext<'_, 'hir>,
|
||||
ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
|
||||
span: Span,
|
||||
) -> &mut HirOrTyGenerics<'hir> {
|
||||
if let HirOrTyGenerics::Ty(ty) = self {
|
||||
let rename_self = matches!(ty.pos, GenericsPosition::Child);
|
||||
let params = ctx.uplift_delegation_generic_params(span, ty.generics, rename_self);
|
||||
if let HirOrTyGenerics::Ty(params) = self {
|
||||
let mut uplift_params = |generics: &'hir [ty::GenericParamDef]| {
|
||||
ctx.uplift_delegation_generic_params(span, generics)
|
||||
};
|
||||
|
||||
*self = HirOrTyGenerics::Hir(DelegationGenerics {
|
||||
generics: params,
|
||||
kind: ty.kind,
|
||||
pos: ty.pos,
|
||||
});
|
||||
let hir_generics = match params {
|
||||
DelegationGenerics::UserSpecified => DelegationGenerics::UserSpecified,
|
||||
DelegationGenerics::Default(params) => {
|
||||
DelegationGenerics::Default(uplift_params(params))
|
||||
}
|
||||
DelegationGenerics::SelfAndUserSpecified(params) => {
|
||||
DelegationGenerics::SelfAndUserSpecified(uplift_params(params))
|
||||
}
|
||||
DelegationGenerics::TraitImpl(params, user_specified) => {
|
||||
DelegationGenerics::TraitImpl(uplift_params(params), *user_specified)
|
||||
}
|
||||
};
|
||||
|
||||
*self = HirOrTyGenerics::Hir(hir_generics);
|
||||
}
|
||||
|
||||
self
|
||||
@@ -134,30 +108,40 @@ impl<'hir> HirOrTyGenerics<'hir> {
|
||||
fn hir_generics_or_empty(&self) -> &'hir hir::Generics<'hir> {
|
||||
match self {
|
||||
HirOrTyGenerics::Ty(_) => hir::Generics::empty(),
|
||||
HirOrTyGenerics::Hir(hir) => hir.generics,
|
||||
HirOrTyGenerics::Hir(hir_generics) => match hir_generics {
|
||||
DelegationGenerics::UserSpecified => hir::Generics::empty(),
|
||||
DelegationGenerics::Default(generics)
|
||||
| DelegationGenerics::SelfAndUserSpecified(generics)
|
||||
| DelegationGenerics::TraitImpl(generics, _) => generics,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn into_generic_args(
|
||||
&self,
|
||||
ctx: &mut LoweringContext<'_, 'hir>,
|
||||
ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
|
||||
add_lifetimes: bool,
|
||||
span: Span,
|
||||
) -> &'hir hir::GenericArgs<'hir> {
|
||||
match self {
|
||||
HirOrTyGenerics::Ty(_) => {
|
||||
bug!("Attempting to get generic args before uplifting to HIR")
|
||||
}
|
||||
HirOrTyGenerics::Hir(hir) => {
|
||||
let add_lifetimes = matches!(hir.pos, GenericsPosition::Parent);
|
||||
ctx.create_generics_args_from_params(hir.generics.params, add_lifetimes, span)
|
||||
}
|
||||
HirOrTyGenerics::Hir(hir_generics) => match hir_generics {
|
||||
DelegationGenerics::UserSpecified => hir::GenericArgs::NONE,
|
||||
DelegationGenerics::Default(generics)
|
||||
| DelegationGenerics::SelfAndUserSpecified(generics)
|
||||
| DelegationGenerics::TraitImpl(generics, _) => {
|
||||
ctx.create_generics_args_from_params(generics.params, add_lifetimes, span)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn args_propagation_details(&self) -> GenericArgsPropagationDetails {
|
||||
match self {
|
||||
HirOrTyGenerics::Ty(ty) => ty.kind.args_propagation_details(),
|
||||
HirOrTyGenerics::Hir(hir) => hir.kind.args_propagation_details(),
|
||||
HirOrTyGenerics::Ty(ty_generics) => ty_generics.args_propagation_details(),
|
||||
HirOrTyGenerics::Hir(hir_generics) => hir_generics.args_propagation_details(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,7 +158,7 @@ impl<'hir> GenericsGenerationResults<'hir> {
|
||||
pub(super) fn all_params(
|
||||
&mut self,
|
||||
span: Span,
|
||||
ctx: &mut LoweringContext<'_, 'hir>,
|
||||
ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
|
||||
) -> impl Iterator<Item = hir::GenericParam<'hir>> {
|
||||
// Now we always call `into_hir_generics` both on child and parent,
|
||||
// however in future we would not do that, when scenarios like
|
||||
@@ -208,7 +192,7 @@ impl<'hir> GenericsGenerationResults<'hir> {
|
||||
pub(super) fn all_predicates(
|
||||
&mut self,
|
||||
span: Span,
|
||||
ctx: &mut LoweringContext<'_, 'hir>,
|
||||
ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
|
||||
) -> impl Iterator<Item = hir::WherePredicate<'hir>> {
|
||||
// Now we always call `into_hir_generics` both on child and parent,
|
||||
// however in future we would not do that, when scenarios like
|
||||
@@ -226,13 +210,12 @@ impl<'hir> GenericsGenerationResults<'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
pub(super) fn uplift_delegation_generics(
|
||||
&mut self,
|
||||
delegation: &Delegation,
|
||||
sig_id: DefId,
|
||||
item_id: NodeId,
|
||||
is_method: bool,
|
||||
) -> GenericsGenerationResults<'hir> {
|
||||
let delegation_parent_kind =
|
||||
self.tcx.def_kind(self.tcx.local_parent(self.local_def_id(item_id)));
|
||||
@@ -248,23 +231,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
if matches!(delegation_parent_kind, DefKind::Impl { of_trait: true }) {
|
||||
// Considering parent generics, during signature inheritance
|
||||
// we will take those args that are in trait impl header trait ref.
|
||||
let parent = DelegationGenerics::trait_impl(&[], true, GenericsPosition::Parent);
|
||||
let parent = GenericsGenerationResult::new(parent);
|
||||
|
||||
let child = DelegationGenerics::trait_impl(
|
||||
sig_params,
|
||||
child_user_specified,
|
||||
GenericsPosition::Child,
|
||||
);
|
||||
let parent = GenericsGenerationResult::new(DelegationGenerics::TraitImpl(&[], true));
|
||||
|
||||
let child = DelegationGenerics::TraitImpl(sig_params, child_user_specified);
|
||||
let child = GenericsGenerationResult::new(child);
|
||||
|
||||
return GenericsGenerationResults {
|
||||
parent,
|
||||
child,
|
||||
self_ty_id: None,
|
||||
propagate_self_ty: false,
|
||||
};
|
||||
return GenericsGenerationResults { parent, child };
|
||||
}
|
||||
|
||||
let delegation_in_free_ctx =
|
||||
@@ -272,56 +244,40 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
let sig_parent = self.tcx.parent(sig_id);
|
||||
let sig_in_trait = matches!(self.tcx.def_kind(sig_parent), DefKind::Trait);
|
||||
let free_to_trait_delegation = delegation_in_free_ctx && sig_in_trait;
|
||||
let generate_self = free_to_trait_delegation && is_method && delegation.qself.is_none();
|
||||
|
||||
let can_add_generics_to_parent = len >= 2
|
||||
&& self.get_resolution_id(segments[len - 2].id).is_some_and(|def_id| {
|
||||
matches!(self.tcx.def_kind(def_id), DefKind::Trait | DefKind::TraitAlias)
|
||||
});
|
||||
|
||||
let generate_self = delegation_in_free_ctx && sig_in_trait;
|
||||
let parent_generics = if can_add_generics_to_parent {
|
||||
let sig_parent_params = &self.tcx.generics_of(sig_parent).own_params[..];
|
||||
|
||||
if segments[len - 2].args.is_some() {
|
||||
if generate_self {
|
||||
// Take only first Self parameter, it is trait so Self must be present.
|
||||
DelegationGenerics {
|
||||
kind: DelegationGenericsKind::SelfAndUserSpecified,
|
||||
generics: &sig_parent_params[..1],
|
||||
pos: GenericsPosition::Parent,
|
||||
}
|
||||
DelegationGenerics::SelfAndUserSpecified(&sig_parent_params[..1])
|
||||
} else {
|
||||
DelegationGenerics::user_specified(&[], GenericsPosition::Parent)
|
||||
DelegationGenerics::UserSpecified
|
||||
}
|
||||
} else {
|
||||
let skip_self = usize::from(!generate_self);
|
||||
DelegationGenerics::default(
|
||||
&sig_parent_params[skip_self..],
|
||||
GenericsPosition::Parent,
|
||||
)
|
||||
DelegationGenerics::Default(&sig_parent_params[skip_self..])
|
||||
}
|
||||
} else {
|
||||
DelegationGenerics::default(&[], GenericsPosition::Parent)
|
||||
DelegationGenerics::<&'hir [ty::GenericParamDef]>::Default(&[])
|
||||
};
|
||||
|
||||
let child_generics = if child_user_specified {
|
||||
let synth_params_index =
|
||||
sig_params.iter().position(|p| p.kind.is_synthetic()).unwrap_or(sig_params.len());
|
||||
|
||||
DelegationGenerics::user_specified(
|
||||
&sig_params[synth_params_index..],
|
||||
GenericsPosition::Child,
|
||||
)
|
||||
DelegationGenerics::UserSpecified
|
||||
} else {
|
||||
DelegationGenerics::default(sig_params, GenericsPosition::Child)
|
||||
DelegationGenerics::Default(sig_params)
|
||||
};
|
||||
|
||||
GenericsGenerationResults {
|
||||
parent: GenericsGenerationResult::new(parent_generics),
|
||||
child: GenericsGenerationResult::new(child_generics),
|
||||
self_ty_id: None,
|
||||
propagate_self_ty: free_to_trait_delegation && !generate_self,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,7 +285,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
&mut self,
|
||||
span: Span,
|
||||
params: &'hir [ty::GenericParamDef],
|
||||
rename_self: bool,
|
||||
) -> &'hir hir::Generics<'hir> {
|
||||
let params = self.arena.alloc_from_iter(params.iter().map(|p| {
|
||||
let def_kind = match p.kind {
|
||||
@@ -338,24 +293,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
GenericParamDefKind::Const { .. } => DefKind::ConstParam,
|
||||
};
|
||||
|
||||
// Rename Self generic param to This so it is properly propagated.
|
||||
// If the user will create a function `fn foo<Self>() {}` with generic
|
||||
// param "Self" then it will not be generated in HIR, the same thing
|
||||
// applies to traits, `trait Trait<Self> {}` will be represented as
|
||||
// `trait Trait {}` in HIR and "unexpected keyword `Self` in generic parameters"
|
||||
// error will be emitted.
|
||||
// Note that we do not rename `Self` to `This` after non-recursive reuse
|
||||
// from Trait, in this case the `Self` should not be propagated
|
||||
// (we rely that implicit `Self` generic param of a trait is named "Self")
|
||||
// and it is OK to have Self generic param generated during lowering.
|
||||
let param_name =
|
||||
if rename_self && p.name == kw::SelfUpper { sym::This } else { p.name };
|
||||
|
||||
let param_ident = Ident::new(param_name, span);
|
||||
let param_ident = Ident::new(p.name, span);
|
||||
let def_name = Some(param_ident.name);
|
||||
let path_data = def_kind.def_path_data(def_name);
|
||||
let node_id = self.next_node_id();
|
||||
|
||||
let def_id = self.create_def(node_id, def_name, def_kind, span);
|
||||
let def_id = self.create_def(node_id, def_name, def_kind, path_data, span);
|
||||
|
||||
let kind = match p.kind {
|
||||
GenericParamDefKind::Lifetime => {
|
||||
|
||||
@@ -8,6 +8,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_errors::msg;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::definitions::DefPathData;
|
||||
use rustc_hir::{HirId, Target, find_attr};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
@@ -28,7 +29,7 @@ use super::{
|
||||
use crate::errors::{InvalidLegacyConstGenericArg, UseConstGenericArg, YieldInClosure};
|
||||
use crate::{AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition, TryBlockScope};
|
||||
|
||||
pub(super) struct WillCreateDefIdsVisitor;
|
||||
struct WillCreateDefIdsVisitor {}
|
||||
|
||||
impl<'v> rustc_ast::visit::Visitor<'v> for WillCreateDefIdsVisitor {
|
||||
type Result = ControlFlow<Span>;
|
||||
@@ -51,7 +52,7 @@ impl<'v> rustc_ast::visit::Visitor<'v> for WillCreateDefIdsVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
fn lower_exprs(&mut self, exprs: &[Box<Expr>]) -> &'hir [hir::Expr<'hir>] {
|
||||
self.arena.alloc_from_iter(exprs.iter().map(|x| self.lower_expr_mut(x)))
|
||||
}
|
||||
@@ -471,19 +472,25 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
for (idx, arg) in args.iter().cloned().enumerate() {
|
||||
if legacy_args_idx.contains(&idx) {
|
||||
let node_id = self.next_node_id();
|
||||
self.create_def(node_id, None, DefKind::AnonConst, f.span);
|
||||
let const_value =
|
||||
if let ControlFlow::Break(span) = WillCreateDefIdsVisitor.visit_expr(&arg) {
|
||||
Box::new(Expr {
|
||||
id: self.next_node_id(),
|
||||
kind: ExprKind::Err(invalid_expr_error(self.tcx, span)),
|
||||
span: f.span,
|
||||
attrs: [].into(),
|
||||
tokens: None,
|
||||
})
|
||||
} else {
|
||||
arg
|
||||
};
|
||||
self.create_def(
|
||||
node_id,
|
||||
None,
|
||||
DefKind::AnonConst,
|
||||
DefPathData::LateAnonConst,
|
||||
f.span,
|
||||
);
|
||||
let mut visitor = WillCreateDefIdsVisitor {};
|
||||
let const_value = if let ControlFlow::Break(span) = visitor.visit_expr(&arg) {
|
||||
Box::new(Expr {
|
||||
id: self.next_node_id(),
|
||||
kind: ExprKind::Err(invalid_expr_error(self.tcx, span)),
|
||||
span: f.span,
|
||||
attrs: [].into(),
|
||||
tokens: None,
|
||||
})
|
||||
} else {
|
||||
arg
|
||||
};
|
||||
|
||||
let anon_const = AnonConst {
|
||||
id: node_id,
|
||||
@@ -755,7 +762,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let fn_decl = self.arena.alloc(hir::FnDecl {
|
||||
inputs,
|
||||
output,
|
||||
fn_decl_kind: hir::FnDeclFlags::default(),
|
||||
c_variadic: false,
|
||||
implicit_self: hir::ImplicitSelfKind::None,
|
||||
lifetime_elision_allowed: false,
|
||||
});
|
||||
|
||||
let body = self.lower_body(move |this| {
|
||||
@@ -1235,7 +1244,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
whole_span: Span,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
// Return early in case of an ordinary assignment.
|
||||
fn is_ordinary(lower_ctx: &mut LoweringContext<'_, '_>, lhs: &Expr) -> bool {
|
||||
fn is_ordinary<'hir>(
|
||||
lower_ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
|
||||
lhs: &Expr,
|
||||
) -> bool {
|
||||
match &lhs.kind {
|
||||
ExprKind::Array(..)
|
||||
| ExprKind::Struct(..)
|
||||
@@ -1290,7 +1302,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
) -> Option<(&'a Option<Box<QSelf>>, &'a Path)> {
|
||||
if let ExprKind::Path(qself, path) = &expr.kind {
|
||||
// Does the path resolve to something disallowed in a tuple struct/variant pattern?
|
||||
if let Some(partial_res) = self.get_partial_res(expr.id) {
|
||||
if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
|
||||
if let Some(res) = partial_res.full_res()
|
||||
&& !res.expected_in_tuple_struct_pat()
|
||||
{
|
||||
@@ -1312,7 +1324,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
) -> Option<(&'a Option<Box<QSelf>>, &'a Path)> {
|
||||
if let ExprKind::Path(qself, path) = &expr.kind {
|
||||
// Does the path resolve to something disallowed in a unit struct/variant pattern?
|
||||
if let Some(partial_res) = self.get_partial_res(expr.id) {
|
||||
if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
|
||||
if let Some(res) = partial_res.full_res()
|
||||
&& !res.expected_in_unit_struct_pat()
|
||||
{
|
||||
|
||||
@@ -7,8 +7,9 @@ use rustc_session::config::FmtDebug;
|
||||
use rustc_span::{ByteSymbol, DesugaringKind, Ident, Span, Symbol, sym};
|
||||
|
||||
use super::LoweringContext;
|
||||
use crate::ResolverAstLoweringExt;
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
pub(crate) fn lower_format_args(&mut self, sp: Span, fmt: &FormatArgs) -> hir::ExprKind<'hir> {
|
||||
// Never call the const constructor of `fmt::Arguments` if the
|
||||
// format_args!() had any arguments _before_ flattening/inlining.
|
||||
@@ -230,7 +231,7 @@ enum ArgumentType {
|
||||
/// <core::fmt::Argument>::new_…(arg)
|
||||
/// ```
|
||||
fn make_argument<'hir>(
|
||||
ctx: &mut LoweringContext<'_, 'hir>,
|
||||
ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
|
||||
sp: Span,
|
||||
arg: &'hir hir::Expr<'hir>,
|
||||
ty: ArgumentType,
|
||||
@@ -277,7 +278,7 @@ fn make_count(
|
||||
}
|
||||
|
||||
fn expand_format_args<'hir>(
|
||||
ctx: &mut LoweringContext<'_, 'hir>,
|
||||
ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
|
||||
macsp: Span,
|
||||
fmt: &FormatArgs,
|
||||
allow_const: bool,
|
||||
|
||||
@@ -13,7 +13,7 @@ use rustc_hir::{
|
||||
};
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym};
|
||||
@@ -24,8 +24,8 @@ use tracing::instrument;
|
||||
use super::errors::{InvalidAbi, InvalidAbiSuggestion, TupleStructWithDefault, UnionWithDefault};
|
||||
use super::stability::{enabled_names, gate_unstable_abi};
|
||||
use super::{
|
||||
AstOwner, FnDeclKind, GenericArgsMode, ImplTraitContext, ImplTraitPosition, LoweringContext,
|
||||
ParamMode, RelaxedBoundForbiddenReason, RelaxedBoundPolicy, ResolverAstLoweringExt,
|
||||
AstOwner, FnDeclKind, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode,
|
||||
RelaxedBoundForbiddenReason, RelaxedBoundPolicy, ResolverAstLoweringExt,
|
||||
};
|
||||
|
||||
/// Wraps either IndexVec (during `hir_crate`), which acts like a primary
|
||||
@@ -38,7 +38,7 @@ pub(super) enum Owners<'a, 'hir> {
|
||||
}
|
||||
|
||||
impl<'hir> Owners<'_, 'hir> {
|
||||
fn get_or_insert_mut(&mut self, def_id: LocalDefId) -> &mut hir::MaybeOwner<'hir> {
|
||||
pub(super) fn get_or_insert_mut(&mut self, def_id: LocalDefId) -> &mut hir::MaybeOwner<'hir> {
|
||||
match self {
|
||||
Owners::IndexVec(index_vec) => {
|
||||
index_vec.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom)
|
||||
@@ -48,9 +48,9 @@ impl<'hir> Owners<'_, 'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct ItemLowerer<'a, 'hir> {
|
||||
pub(super) struct ItemLowerer<'a, 'hir, R> {
|
||||
pub(super) tcx: TyCtxt<'hir>,
|
||||
pub(super) resolver: &'a ResolverAstLowering<'hir>,
|
||||
pub(super) resolver: &'a mut R,
|
||||
pub(super) ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
|
||||
pub(super) owners: Owners<'a, 'hir>,
|
||||
}
|
||||
@@ -74,11 +74,11 @@ fn add_ty_alias_where_clause(
|
||||
if before.0 || !after.0 { before } else { after };
|
||||
}
|
||||
|
||||
impl<'hir> ItemLowerer<'_, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> ItemLowerer<'_, 'hir, R> {
|
||||
fn with_lctx(
|
||||
&mut self,
|
||||
owner: NodeId,
|
||||
f: impl for<'a> FnOnce(&mut LoweringContext<'a, 'hir>) -> hir::OwnerNode<'hir>,
|
||||
f: impl FnOnce(&mut LoweringContext<'_, 'hir, R>) -> hir::OwnerNode<'hir>,
|
||||
) {
|
||||
let mut lctx = LoweringContext::new(self.tcx, self.resolver);
|
||||
lctx.with_hir_id_owner(owner, |lctx| f(lctx));
|
||||
@@ -122,7 +122,7 @@ impl<'hir> ItemLowerer<'_, 'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
pub(super) fn lower_mod(
|
||||
&mut self,
|
||||
items: &[Box<Item>],
|
||||
@@ -213,14 +213,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
i: &ItemKind,
|
||||
) -> Vec<hir::Attribute> {
|
||||
match i {
|
||||
ItemKind::Fn(box Fn { eii_impls, .. })
|
||||
| ItemKind::Static(box StaticItem { eii_impls, .. })
|
||||
if eii_impls.is_empty() =>
|
||||
{
|
||||
Vec::new()
|
||||
}
|
||||
ItemKind::Fn(box Fn { eii_impls, .. })
|
||||
| ItemKind::Static(box StaticItem { eii_impls, .. }) => {
|
||||
ItemKind::Fn(box Fn { eii_impls, .. }) if eii_impls.is_empty() => Vec::new(),
|
||||
ItemKind::Fn(box Fn { eii_impls, .. }) => {
|
||||
vec![hir::Attribute::Parsed(AttributeKind::EiiImpls(
|
||||
eii_impls.iter().map(|i| self.lower_eii_impl(i)).collect(),
|
||||
))]
|
||||
@@ -232,6 +226,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
ItemKind::ExternCrate(..)
|
||||
| ItemKind::Use(..)
|
||||
| ItemKind::Static(..)
|
||||
| ItemKind::Const(..)
|
||||
| ItemKind::ConstBlock(..)
|
||||
| ItemKind::Mod(..)
|
||||
@@ -307,7 +302,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
mutability: m,
|
||||
expr: e,
|
||||
define_opaque,
|
||||
eii_impls: _,
|
||||
}) => {
|
||||
let ident = self.lower_ident(*ident);
|
||||
let ty = self
|
||||
@@ -543,17 +537,17 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
})
|
||||
}
|
||||
ItemKind::Trait(box Trait {
|
||||
impl_restriction,
|
||||
constness,
|
||||
is_auto,
|
||||
safety,
|
||||
// FIXME(impl_restrictions): lower to HIR
|
||||
impl_restriction: _,
|
||||
ident,
|
||||
generics,
|
||||
bounds,
|
||||
items,
|
||||
}) => {
|
||||
let constness = self.lower_constness(*constness);
|
||||
let impl_restriction = self.lower_impl_restriction(impl_restriction);
|
||||
let ident = self.lower_ident(*ident);
|
||||
let (generics, (safety, items, bounds)) = self.lower_generics(
|
||||
generics,
|
||||
@@ -572,16 +566,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
(safety, items, bounds)
|
||||
},
|
||||
);
|
||||
hir::ItemKind::Trait(
|
||||
impl_restriction,
|
||||
constness,
|
||||
*is_auto,
|
||||
safety,
|
||||
ident,
|
||||
generics,
|
||||
bounds,
|
||||
items,
|
||||
)
|
||||
hir::ItemKind::Trait(constness, *is_auto, safety, ident, generics, bounds, items)
|
||||
}
|
||||
ItemKind::TraitAlias(box TraitAlias { constness, ident, generics, bounds }) => {
|
||||
let constness = self.lower_constness(*constness);
|
||||
@@ -635,7 +620,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
|
||||
fn lower_path_simple_eii(&mut self, id: NodeId, path: &Path) -> Option<DefId> {
|
||||
let res = self.get_partial_res(id)?;
|
||||
let res = self.resolver.get_partial_res(id)?;
|
||||
let Some(did) = res.expect_full_res().opt_def_id() else {
|
||||
self.dcx().span_delayed_bug(path.span, "should have errored in resolve");
|
||||
return None;
|
||||
@@ -832,7 +817,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
expr: _,
|
||||
safety,
|
||||
define_opaque,
|
||||
eii_impls: _,
|
||||
}) => {
|
||||
let ty = self
|
||||
.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
|
||||
@@ -1336,6 +1320,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
ImplItemImplKind::Trait {
|
||||
defaultness,
|
||||
trait_item_def_id: self
|
||||
.resolver
|
||||
.get_partial_res(i.id)
|
||||
.and_then(|r| r.expect_full_res().opt_def_id())
|
||||
.ok_or_else(|| {
|
||||
@@ -1531,7 +1516,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
pub(crate) fn lower_coroutine_body_with_moved_arguments(
|
||||
&mut self,
|
||||
decl: &FnDecl,
|
||||
lower_body: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::Expr<'hir>,
|
||||
lower_body: impl FnOnce(&mut LoweringContext<'_, 'hir, R>) -> hir::Expr<'hir>,
|
||||
fn_decl_span: Span,
|
||||
body_span: Span,
|
||||
coroutine_kind: CoroutineKind,
|
||||
@@ -1668,7 +1653,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
parameters.push(new_parameter);
|
||||
}
|
||||
|
||||
let mkbody = |this: &mut LoweringContext<'_, 'hir>| {
|
||||
let mkbody = |this: &mut LoweringContext<'_, 'hir, R>| {
|
||||
// Create a block from the user's function body:
|
||||
let user_body = lower_body(this);
|
||||
|
||||
@@ -1846,38 +1831,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn lower_impl_restriction(
|
||||
&mut self,
|
||||
r: &ImplRestriction,
|
||||
) -> &'hir hir::ImplRestriction<'hir> {
|
||||
let kind = match &r.kind {
|
||||
RestrictionKind::Unrestricted => hir::RestrictionKind::Unrestricted,
|
||||
RestrictionKind::Restricted { path, id, shorthand: _ } => {
|
||||
let res = self.get_partial_res(*id);
|
||||
if let Some(did) = res.and_then(|res| res.expect_full_res().opt_def_id()) {
|
||||
hir::RestrictionKind::Restricted(self.arena.alloc(hir::Path {
|
||||
res: did,
|
||||
segments: self.arena.alloc_from_iter(path.segments.iter().map(|segment| {
|
||||
self.lower_path_segment(
|
||||
path.span,
|
||||
segment,
|
||||
ParamMode::Explicit,
|
||||
GenericArgsMode::Err,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
)
|
||||
})),
|
||||
span: self.lower_span(path.span),
|
||||
}))
|
||||
} else {
|
||||
self.dcx().span_delayed_bug(path.span, "should have errored in resolve");
|
||||
hir::RestrictionKind::Unrestricted
|
||||
}
|
||||
}
|
||||
};
|
||||
self.arena.alloc(hir::ImplRestriction { kind, span: self.lower_span(r.span) })
|
||||
}
|
||||
|
||||
/// Return the pair of the lowered `generics` as `hir::Generics` and the evaluation of `f` with
|
||||
/// the carried impl trait definitions and bounds.
|
||||
#[instrument(level = "debug", skip(self, f))]
|
||||
@@ -1919,7 +1872,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
// Introduce extra lifetimes if late resolution tells us to.
|
||||
let extra_lifetimes = self.resolver.extra_lifetime_params(parent_node_id);
|
||||
params.extend(extra_lifetimes.into_iter().filter_map(|&(ident, node_id, res)| {
|
||||
params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| {
|
||||
self.lifetime_res_to_generic_param(
|
||||
ident,
|
||||
node_id,
|
||||
@@ -1961,7 +1914,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
return;
|
||||
};
|
||||
let define_opaque = define_opaque.iter().filter_map(|(id, path)| {
|
||||
let res = self.get_partial_res(*id);
|
||||
let res = self.resolver.get_partial_res(*id);
|
||||
let Some(did) = res.and_then(|res| res.expect_full_res().opt_def_id()) else {
|
||||
self.dcx().span_delayed_bug(path.span, "should have errored in resolve");
|
||||
return None;
|
||||
|
||||
@@ -39,9 +39,9 @@ use std::mem;
|
||||
use std::sync::Arc;
|
||||
|
||||
use rustc_ast::node_id::NodeMap;
|
||||
use rustc_ast::visit::Visitor;
|
||||
use rustc_ast::visit::AssocCtxt;
|
||||
use rustc_ast::{self as ast, *};
|
||||
use rustc_attr_parsing::{AttributeParser, EmitAttribute, Late, OmitDoc};
|
||||
use rustc_attr_parsing::{AttributeParser, Late, OmitDoc};
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
@@ -51,8 +51,8 @@ use rustc_data_structures::tagged_ptr::TaggedRef;
|
||||
use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle};
|
||||
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
|
||||
use rustc_hir::definitions::PerParentDisambiguatorState;
|
||||
use rustc_hir::lints::{AttributeLint, DelayedLint, DynAttribute};
|
||||
use rustc_hir::definitions::{DefPathData, DisambiguatorState};
|
||||
use rustc_hir::lints::{AttributeLint, DelayedLint};
|
||||
use rustc_hir::{
|
||||
self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LifetimeSource,
|
||||
LifetimeSyntax, ParamName, Target, TraitCandidate, find_attr,
|
||||
@@ -91,10 +91,10 @@ mod pat;
|
||||
mod path;
|
||||
pub mod stability;
|
||||
|
||||
struct LoweringContext<'a, 'hir> {
|
||||
struct LoweringContext<'a, 'hir, R> {
|
||||
tcx: TyCtxt<'hir>,
|
||||
resolver: &'a ResolverAstLowering<'hir>,
|
||||
current_disambiguator: PerParentDisambiguatorState,
|
||||
resolver: &'a mut R,
|
||||
disambiguator: DisambiguatorState,
|
||||
|
||||
/// Used to allocate HIR nodes.
|
||||
arena: &'hir hir::Arena<'hir>,
|
||||
@@ -138,16 +138,6 @@ struct LoweringContext<'a, 'hir> {
|
||||
/// NodeIds that are lowered inside the current HIR owner. Only used for duplicate lowering check.
|
||||
#[cfg(debug_assertions)]
|
||||
node_id_to_local_id: NodeMap<hir::ItemLocalId>,
|
||||
/// The `NodeId` space is split in two.
|
||||
/// `0..resolver.next_node_id` are created by the resolver on the AST.
|
||||
/// The higher part `resolver.next_node_id..next_node_id` are created during lowering.
|
||||
next_node_id: NodeId,
|
||||
/// Maps the `NodeId`s created during lowering to `LocalDefId`s.
|
||||
node_id_to_def_id: NodeMap<LocalDefId>,
|
||||
/// Overlay over resolver's `partial_res_map` used by delegation.
|
||||
/// This only contains `PartialRes::new(Res::Local(self_param_id))`,
|
||||
/// so we only store `self_param_id`.
|
||||
partial_res_overrides: NodeMap<NodeId>,
|
||||
|
||||
allow_contracts: Arc<[Symbol]>,
|
||||
allow_try_trait: Arc<[Symbol]>,
|
||||
@@ -163,13 +153,13 @@ struct LoweringContext<'a, 'hir> {
|
||||
attribute_parser: AttributeParser<'hir>,
|
||||
}
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
fn new(tcx: TyCtxt<'hir>, resolver: &'a ResolverAstLowering<'hir>) -> Self {
|
||||
impl<'a, 'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'a, 'hir, R> {
|
||||
fn new(tcx: TyCtxt<'hir>, resolver: &'a mut R) -> Self {
|
||||
let registered_tools = tcx.registered_tools(()).iter().map(|x| x.name).collect();
|
||||
Self {
|
||||
tcx,
|
||||
resolver,
|
||||
current_disambiguator: Default::default(),
|
||||
disambiguator: DisambiguatorState::new(),
|
||||
arena: tcx.hir_arena,
|
||||
|
||||
// HirId handling.
|
||||
@@ -184,9 +174,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
#[cfg(debug_assertions)]
|
||||
node_id_to_local_id: Default::default(),
|
||||
trait_map: Default::default(),
|
||||
next_node_id: resolver.next_node_id,
|
||||
node_id_to_def_id: NodeMap::default(),
|
||||
partial_res_overrides: NodeMap::default(),
|
||||
|
||||
// Lowering state.
|
||||
try_block_scope: TryBlockScope::Function,
|
||||
@@ -250,6 +237,81 @@ impl SpanLowerer {
|
||||
}
|
||||
}
|
||||
|
||||
struct ResolverDelayedAstLowering<'a, 'tcx> {
|
||||
node_id_to_def_id: NodeMap<LocalDefId>,
|
||||
partial_res_map: NodeMap<PartialRes>,
|
||||
next_node_id: NodeId,
|
||||
base: &'a ResolverAstLowering<'tcx>,
|
||||
}
|
||||
|
||||
// FIXME(fn_delegation): delegate this trait impl to `self.base`
|
||||
impl<'a, 'tcx> ResolverAstLoweringExt<'tcx> for ResolverDelayedAstLowering<'a, 'tcx> {
|
||||
fn legacy_const_generic_args(&self, expr: &Expr, tcx: TyCtxt<'tcx>) -> Option<Vec<usize>> {
|
||||
self.base.legacy_const_generic_args(expr, tcx)
|
||||
}
|
||||
|
||||
fn get_partial_res(&self, id: NodeId) -> Option<PartialRes> {
|
||||
self.partial_res_map.get(&id).copied().or_else(|| self.base.get_partial_res(id))
|
||||
}
|
||||
|
||||
fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res<NodeId>>> {
|
||||
self.base.get_import_res(id)
|
||||
}
|
||||
|
||||
fn get_label_res(&self, id: NodeId) -> Option<NodeId> {
|
||||
self.base.get_label_res(id)
|
||||
}
|
||||
|
||||
fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes> {
|
||||
self.base.get_lifetime_res(id)
|
||||
}
|
||||
|
||||
fn extra_lifetime_params(&self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> {
|
||||
self.base.extra_lifetime_params(id)
|
||||
}
|
||||
|
||||
fn delegation_info(&self, id: LocalDefId) -> Option<&DelegationInfo> {
|
||||
self.base.delegation_info(id)
|
||||
}
|
||||
|
||||
fn opt_local_def_id(&self, id: NodeId) -> Option<LocalDefId> {
|
||||
self.node_id_to_def_id.get(&id).copied().or_else(|| self.base.opt_local_def_id(id))
|
||||
}
|
||||
|
||||
fn local_def_id(&self, id: NodeId) -> LocalDefId {
|
||||
self.opt_local_def_id(id).expect("must have def_id")
|
||||
}
|
||||
|
||||
fn lifetime_elision_allowed(&self, id: NodeId) -> bool {
|
||||
self.base.lifetime_elision_allowed(id)
|
||||
}
|
||||
|
||||
fn insert_new_def_id(&mut self, node_id: NodeId, def_id: LocalDefId) {
|
||||
self.node_id_to_def_id.insert(node_id, def_id);
|
||||
}
|
||||
|
||||
fn insert_partial_res(&mut self, node_id: NodeId, res: PartialRes) {
|
||||
self.partial_res_map.insert(node_id, res);
|
||||
}
|
||||
|
||||
fn trait_candidates(&self, node_id: NodeId) -> Option<&'tcx [hir::TraitCandidate<'tcx>]> {
|
||||
self.base.trait_candidates(node_id)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn next_node_id(&mut self) -> NodeId {
|
||||
next_node_id(&mut self.next_node_id)
|
||||
}
|
||||
}
|
||||
|
||||
fn next_node_id(current_id: &mut NodeId) -> NodeId {
|
||||
let start = *current_id;
|
||||
let next = start.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
|
||||
*current_id = ast::NodeId::from_u32(next);
|
||||
|
||||
start
|
||||
}
|
||||
|
||||
#[extension(trait ResolverAstLoweringExt<'tcx>)]
|
||||
impl<'tcx> ResolverAstLowering<'tcx> {
|
||||
fn legacy_const_generic_args(&self, expr: &Expr, tcx: TyCtxt<'tcx>) -> Option<Vec<usize>> {
|
||||
@@ -263,10 +325,7 @@ impl<'tcx> ResolverAstLowering<'tcx> {
|
||||
return None;
|
||||
}
|
||||
|
||||
// We do not need to look at `partial_res_overrides`. That map only contains overrides for
|
||||
// `self_param` locals. And here we are looking for the function definition that `expr`
|
||||
// resolves to.
|
||||
let def_id = self.partial_res_map.get(&expr.id)?.full_res()?.opt_def_id()?;
|
||||
let def_id = self.get_partial_res(expr.id)?.full_res()?.opt_def_id()?;
|
||||
|
||||
// We only support cross-crate argument rewriting. Uses
|
||||
// within the same crate should be updated to use the new
|
||||
@@ -283,6 +342,10 @@ impl<'tcx> ResolverAstLowering<'tcx> {
|
||||
.map(|fn_indexes| fn_indexes.iter().map(|(num, _)| *num).collect())
|
||||
}
|
||||
|
||||
fn get_partial_res(&self, id: NodeId) -> Option<PartialRes> {
|
||||
self.partial_res_map.get(&id).copied()
|
||||
}
|
||||
|
||||
/// Obtains per-namespace resolutions for `use` statement with the given `NodeId`.
|
||||
fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res<NodeId>>> {
|
||||
self.import_res_map.get(&id).copied().unwrap_or_default()
|
||||
@@ -305,8 +368,8 @@ impl<'tcx> ResolverAstLowering<'tcx> {
|
||||
///
|
||||
/// The extra lifetimes that appear from the parenthesized `Fn`-trait desugaring
|
||||
/// should appear at the enclosing `PolyTraitRef`.
|
||||
fn extra_lifetime_params(&self, id: NodeId) -> &[(Ident, NodeId, LifetimeRes)] {
|
||||
self.extra_lifetime_params_map.get(&id).map_or(&[], |v| &v[..])
|
||||
fn extra_lifetime_params(&self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> {
|
||||
self.extra_lifetime_params_map.get(&id).cloned().unwrap_or_default()
|
||||
}
|
||||
|
||||
fn delegation_info(&self, id: LocalDefId) -> Option<&DelegationInfo> {
|
||||
@@ -324,6 +387,23 @@ impl<'tcx> ResolverAstLowering<'tcx> {
|
||||
fn lifetime_elision_allowed(&self, id: NodeId) -> bool {
|
||||
self.lifetime_elision_allowed.contains(&id)
|
||||
}
|
||||
|
||||
fn insert_new_def_id(&mut self, node_id: NodeId, def_id: LocalDefId) {
|
||||
self.node_id_to_def_id.insert(node_id, def_id);
|
||||
}
|
||||
|
||||
fn insert_partial_res(&mut self, node_id: NodeId, res: PartialRes) {
|
||||
self.partial_res_map.insert(node_id, res);
|
||||
}
|
||||
|
||||
fn trait_candidates(&self, node_id: NodeId) -> Option<&'tcx [hir::TraitCandidate<'tcx>]> {
|
||||
self.trait_map.get(&node_id).copied()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn next_node_id(&mut self) -> NodeId {
|
||||
next_node_id(&mut self.next_node_id)
|
||||
}
|
||||
}
|
||||
|
||||
/// How relaxed bounds `?Trait` should be treated.
|
||||
@@ -464,7 +544,7 @@ enum TryBlockScope {
|
||||
}
|
||||
|
||||
fn index_crate<'a, 'b>(
|
||||
resolver: &'b ResolverAstLowering<'b>,
|
||||
resolver: &'b impl ResolverAstLoweringExt<'a>,
|
||||
krate: &'a Crate,
|
||||
) -> IndexVec<LocalDefId, AstOwner<'a>> {
|
||||
let mut indexer = Indexer { resolver, index: IndexVec::new() };
|
||||
@@ -474,12 +554,12 @@ fn index_crate<'a, 'b>(
|
||||
|
||||
return indexer.index;
|
||||
|
||||
struct Indexer<'a, 'b> {
|
||||
resolver: &'b ResolverAstLowering<'b>,
|
||||
struct Indexer<'a, 'b, R> {
|
||||
resolver: &'b R,
|
||||
index: IndexVec<LocalDefId, AstOwner<'a>>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> visit::Visitor<'a> for Indexer<'a, 'b> {
|
||||
impl<'a, 'b, R: ResolverAstLoweringExt<'a>> visit::Visitor<'a> for Indexer<'a, 'b, R> {
|
||||
fn visit_attribute(&mut self, _: &'a Attribute) {
|
||||
// We do not want to lower expressions that appear in attributes,
|
||||
// as they are not accessible to the rest of the HIR.
|
||||
@@ -536,7 +616,7 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> mid_hir::Crate<'_> {
|
||||
tcx.ensure_done().early_lint_checks(());
|
||||
tcx.ensure_done().debugger_visualizers(LOCAL_CRATE);
|
||||
tcx.ensure_done().get_lang_items(());
|
||||
let (resolver, krate) = tcx.resolver_for_lowering().steal();
|
||||
let (mut resolver, krate) = tcx.resolver_for_lowering().steal();
|
||||
|
||||
let ast_index = index_crate(&resolver, &krate);
|
||||
let mut owners = IndexVec::from_fn_n(
|
||||
@@ -546,7 +626,7 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> mid_hir::Crate<'_> {
|
||||
|
||||
let mut lowerer = item::ItemLowerer {
|
||||
tcx,
|
||||
resolver: &resolver,
|
||||
resolver: &mut resolver,
|
||||
ast_index: &ast_index,
|
||||
owners: Owners::IndexVec(&mut owners),
|
||||
};
|
||||
@@ -554,13 +634,29 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> mid_hir::Crate<'_> {
|
||||
let mut delayed_ids: FxIndexSet<LocalDefId> = Default::default();
|
||||
|
||||
for def_id in ast_index.indices() {
|
||||
match &ast_index[def_id] {
|
||||
AstOwner::Item(Item { kind: ItemKind::Delegation { .. }, .. })
|
||||
| AstOwner::AssocItem(Item { kind: AssocItemKind::Delegation { .. }, .. }, _) => {
|
||||
delayed_ids.insert(def_id);
|
||||
let delayed_owner_kind = match &ast_index[def_id] {
|
||||
AstOwner::Item(Item { kind: ItemKind::Delegation(_), .. }) => {
|
||||
Some(hir::DelayedOwnerKind::Item)
|
||||
}
|
||||
_ => lowerer.lower_node(def_id),
|
||||
AstOwner::AssocItem(Item { kind: AssocItemKind::Delegation(_), .. }, ctx) => {
|
||||
Some(match ctx {
|
||||
AssocCtxt::Trait => hir::DelayedOwnerKind::TraitItem,
|
||||
AssocCtxt::Impl { .. } => hir::DelayedOwnerKind::ImplItem,
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
if let Some(kind) = delayed_owner_kind {
|
||||
delayed_ids.insert(def_id);
|
||||
|
||||
let owner = lowerer.owners.get_or_insert_mut(def_id);
|
||||
if let hir::MaybeOwner::Phantom = owner {
|
||||
*owner = hir::MaybeOwner::Delayed(kind)
|
||||
}
|
||||
} else {
|
||||
lowerer.lower_node(def_id);
|
||||
}
|
||||
}
|
||||
|
||||
// Don't hash unless necessary, because it's expensive.
|
||||
@@ -581,10 +677,18 @@ pub fn lower_delayed_owner(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
// as it is too bad to reindex whole crate on each delegation lowering.
|
||||
let ast_index = index_crate(resolver, krate);
|
||||
|
||||
let mut resolver = ResolverDelayedAstLowering {
|
||||
next_node_id: resolver.next_node_id,
|
||||
partial_res_map: Default::default(),
|
||||
node_id_to_def_id: Default::default(),
|
||||
base: resolver,
|
||||
};
|
||||
|
||||
let mut map = Default::default();
|
||||
|
||||
let mut lowerer = item::ItemLowerer {
|
||||
tcx,
|
||||
resolver: &resolver,
|
||||
resolver: &mut resolver,
|
||||
ast_index: &ast_index,
|
||||
owners: Owners::Map(&mut map),
|
||||
};
|
||||
@@ -623,12 +727,13 @@ enum GenericArgsMode {
|
||||
Silence,
|
||||
}
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
fn create_def(
|
||||
&mut self,
|
||||
node_id: NodeId,
|
||||
node_id: ast::NodeId,
|
||||
name: Option<Symbol>,
|
||||
def_kind: DefKind,
|
||||
def_path_data: DefPathData,
|
||||
span: Span,
|
||||
) -> LocalDefId {
|
||||
let parent = self.current_hir_id_owner.def_id;
|
||||
@@ -644,42 +749,29 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let def_id = self
|
||||
.tcx
|
||||
.at(span)
|
||||
.create_def(parent, name, def_kind, None, &mut self.current_disambiguator)
|
||||
.create_def(parent, name, def_kind, Some(def_path_data), &mut self.disambiguator)
|
||||
.def_id();
|
||||
|
||||
debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id);
|
||||
self.node_id_to_def_id.insert(node_id, def_id);
|
||||
self.resolver.insert_new_def_id(node_id, def_id);
|
||||
|
||||
def_id
|
||||
}
|
||||
|
||||
fn next_node_id(&mut self) -> NodeId {
|
||||
let start = self.next_node_id;
|
||||
let next = start.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
|
||||
self.next_node_id = NodeId::from_u32(next);
|
||||
start
|
||||
self.resolver.next_node_id()
|
||||
}
|
||||
|
||||
/// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name
|
||||
/// resolver (if any).
|
||||
fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
|
||||
self.node_id_to_def_id
|
||||
.get(&node)
|
||||
.or_else(|| self.resolver.node_id_to_def_id.get(&node))
|
||||
.copied()
|
||||
self.resolver.opt_local_def_id(node)
|
||||
}
|
||||
|
||||
fn local_def_id(&self, node: NodeId) -> LocalDefId {
|
||||
self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{node:?}`"))
|
||||
}
|
||||
|
||||
fn get_partial_res(&self, id: NodeId) -> Option<PartialRes> {
|
||||
match self.partial_res_overrides.get(&id) {
|
||||
Some(self_param_id) => Some(PartialRes::new(Res::Local(*self_param_id))),
|
||||
None => self.resolver.partial_res_map.get(&id).copied(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Given the id of an owner node in the AST, returns the corresponding `OwnerId`.
|
||||
fn owner_id(&self, node: NodeId) -> hir::OwnerId {
|
||||
hir::OwnerId { def_id: self.local_def_id(node) }
|
||||
@@ -697,16 +789,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
f: impl FnOnce(&mut Self) -> hir::OwnerNode<'hir>,
|
||||
) {
|
||||
let owner_id = self.owner_id(owner);
|
||||
let def_id = owner_id.def_id;
|
||||
|
||||
let new_disambig = self
|
||||
.resolver
|
||||
.disambiguators
|
||||
.get(&def_id)
|
||||
.map(|s| s.steal())
|
||||
.unwrap_or_else(|| PerParentDisambiguatorState::new(def_id));
|
||||
|
||||
let disambiguator = std::mem::replace(&mut self.current_disambiguator, new_disambig);
|
||||
let current_attrs = std::mem::take(&mut self.attrs);
|
||||
let current_bodies = std::mem::take(&mut self.bodies);
|
||||
let current_define_opaque = std::mem::take(&mut self.define_opaque);
|
||||
@@ -741,7 +824,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
assert!(self.impl_trait_bounds.is_empty());
|
||||
let info = self.make_owner_info(item);
|
||||
|
||||
self.current_disambiguator = disambiguator;
|
||||
self.attrs = current_attrs;
|
||||
self.bodies = current_bodies;
|
||||
self.define_opaque = current_define_opaque;
|
||||
@@ -781,12 +863,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let bodies = SortedMap::from_presorted_elements(bodies);
|
||||
|
||||
// Don't hash unless necessary, because it's expensive.
|
||||
let rustc_middle::hir::Hashes { opt_hash_including_bodies, attrs_hash } =
|
||||
self.tcx.hash_owner_nodes(node, &bodies, &attrs, define_opaque);
|
||||
let rustc_middle::hir::Hashes { opt_hash_including_bodies, attrs_hash, delayed_lints_hash } =
|
||||
self.tcx.hash_owner_nodes(node, &bodies, &attrs, &delayed_lints, define_opaque);
|
||||
let num_nodes = self.item_local_id_counter.as_usize();
|
||||
let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes);
|
||||
let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies };
|
||||
let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash, define_opaque };
|
||||
let delayed_lints =
|
||||
hir::lints::DelayedLints { lints: delayed_lints, opt_hash: delayed_lints_hash };
|
||||
|
||||
self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map, delayed_lints })
|
||||
}
|
||||
@@ -810,8 +894,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id)));
|
||||
}
|
||||
|
||||
if let Some(traits) = self.resolver.trait_map.get(&ast_node_id) {
|
||||
self.trait_map.insert(hir_id.local_id, &traits[..]);
|
||||
if let Some(traits) = self.resolver.trait_candidates(ast_node_id) {
|
||||
self.trait_map.insert(hir_id.local_id, traits);
|
||||
}
|
||||
|
||||
// Check whether the same `NodeId` is lowered more than once.
|
||||
@@ -852,7 +936,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
|
||||
fn expect_full_res(&mut self, id: NodeId) -> Res<NodeId> {
|
||||
self.get_partial_res(id).map_or(Res::Err, |pr| pr.expect_full_res())
|
||||
self.resolver.get_partial_res(id).map_or(Res::Err, |pr| pr.expect_full_res())
|
||||
}
|
||||
|
||||
fn lower_import_res(&mut self, id: NodeId, span: Span) -> PerNS<Option<Res>> {
|
||||
@@ -947,6 +1031,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
param,
|
||||
Some(kw::UnderscoreLifetime),
|
||||
DefKind::LifetimeParam,
|
||||
DefPathData::DesugaredAnonymousLifetime,
|
||||
ident.span,
|
||||
);
|
||||
debug!(?_def_id);
|
||||
@@ -990,8 +1075,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let extra_lifetimes = self.resolver.extra_lifetime_params(binder);
|
||||
debug!(?extra_lifetimes);
|
||||
let extra_lifetimes: Vec<_> = extra_lifetimes
|
||||
.iter()
|
||||
.filter_map(|&(ident, node_id, res)| {
|
||||
.into_iter()
|
||||
.filter_map(|(ident, node_id, res)| {
|
||||
self.lifetime_res_to_generic_param(
|
||||
ident,
|
||||
node_id,
|
||||
@@ -1098,23 +1183,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
target,
|
||||
OmitDoc::Lower,
|
||||
|s| l.lower(s),
|
||||
|lint_id, span, kind| match kind {
|
||||
EmitAttribute::Static(attr_kind) => {
|
||||
self.delayed_lints.push(DelayedLint::AttributeParsing(AttributeLint {
|
||||
lint_id,
|
||||
id: target_hir_id,
|
||||
span,
|
||||
kind: attr_kind,
|
||||
}));
|
||||
}
|
||||
EmitAttribute::Dynamic(callback) => {
|
||||
self.delayed_lints.push(DelayedLint::Dynamic(DynAttribute {
|
||||
lint_id,
|
||||
id: target_hir_id,
|
||||
span,
|
||||
callback,
|
||||
}));
|
||||
}
|
||||
|lint_id, span, kind| {
|
||||
self.delayed_lints.push(DelayedLint::AttributeParsing(AttributeLint {
|
||||
lint_id,
|
||||
id: target_hir_id,
|
||||
span,
|
||||
kind,
|
||||
}));
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -1317,6 +1392,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// FIXME: Should we be handling `(PATH_TO_CONST)`?
|
||||
TyKind::Path(None, path) => {
|
||||
if let Some(res) = self
|
||||
.resolver
|
||||
.get_partial_res(ty.id)
|
||||
.and_then(|partial_res| partial_res.full_res())
|
||||
{
|
||||
@@ -1367,7 +1443,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// The other cases when a qpath should be opportunistically made a trait object are handled
|
||||
// by `ty_path`.
|
||||
if qself.is_none()
|
||||
&& let Some(partial_res) = self.get_partial_res(t.id)
|
||||
&& let Some(partial_res) = self.resolver.get_partial_res(t.id)
|
||||
&& let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = partial_res.full_res()
|
||||
{
|
||||
let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
|
||||
@@ -1721,7 +1797,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let [segment] = path.segments.as_slice() else {
|
||||
panic!();
|
||||
};
|
||||
let res = self.get_partial_res(*id).map_or(Res::Err, |partial_res| {
|
||||
let res = self.resolver.get_partial_res(*id).map_or(Res::Err, |partial_res| {
|
||||
partial_res.full_res().expect("no partial res expected for precise capture arg")
|
||||
});
|
||||
hir::PreciseCapturingArg::Param(hir::PreciseCapturingNonLifetimeArg {
|
||||
@@ -1772,7 +1848,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// as they are not explicit in HIR/Ty function signatures.
|
||||
// (instead, the `c_variadic` flag is set to `true`)
|
||||
let mut inputs = &decl.inputs[..];
|
||||
if decl.c_variadic() {
|
||||
if c_variadic {
|
||||
inputs = &inputs[..inputs.len() - 1];
|
||||
}
|
||||
let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| {
|
||||
@@ -1835,8 +1911,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
},
|
||||
};
|
||||
|
||||
let fn_decl_kind = hir::FnDeclFlags::default()
|
||||
.set_implicit_self(decl.inputs.get(0).map_or(hir::ImplicitSelfKind::None, |arg| {
|
||||
self.arena.alloc(hir::FnDecl {
|
||||
inputs,
|
||||
output,
|
||||
c_variadic,
|
||||
lifetime_elision_allowed: self.resolver.lifetime_elision_allowed(fn_node_id),
|
||||
implicit_self: decl.inputs.get(0).map_or(hir::ImplicitSelfKind::None, |arg| {
|
||||
let is_mutable_pat = matches!(
|
||||
arg.pat.kind,
|
||||
PatKind::Ident(hir::BindingMode(_, Mutability::Mut), ..)
|
||||
@@ -1858,11 +1938,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
}
|
||||
_ => hir::ImplicitSelfKind::None,
|
||||
}
|
||||
}))
|
||||
.set_lifetime_elision_allowed(self.resolver.lifetime_elision_allowed(fn_node_id))
|
||||
.set_c_variadic(c_variadic);
|
||||
|
||||
self.arena.alloc(hir::FnDecl { inputs, output, fn_decl_kind })
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
// Transforms `-> T` for `async fn` into `-> OpaqueTy { .. }`
|
||||
@@ -2159,22 +2236,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// since later compiler stages cannot handle them (and shouldn't need to be able to).
|
||||
let default = default
|
||||
.as_ref()
|
||||
.filter(|anon_const| match source {
|
||||
.filter(|_| match source {
|
||||
hir::GenericParamSource::Generics => true,
|
||||
hir::GenericParamSource::Binder => {
|
||||
let err = errors::GenericParamDefaultInBinder { span: param.span() };
|
||||
if expr::WillCreateDefIdsVisitor
|
||||
.visit_expr(&anon_const.value)
|
||||
.is_break()
|
||||
{
|
||||
// FIXME(mgca): make this non-fatal once we have a better way
|
||||
// to handle nested items in anno const from binder
|
||||
// Issue: https://github.com/rust-lang/rust/issues/123629
|
||||
self.dcx().emit_fatal(err)
|
||||
} else {
|
||||
self.dcx().emit_err(err);
|
||||
false
|
||||
}
|
||||
self.dcx().emit_err(errors::GenericParamDefaultInBinder {
|
||||
span: param.span(),
|
||||
});
|
||||
|
||||
false
|
||||
}
|
||||
})
|
||||
.map(|def| self.lower_anon_const_to_const_arg_and_alloc(def));
|
||||
@@ -2250,7 +2319,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
match rbp {
|
||||
RelaxedBoundPolicy::Allowed => return,
|
||||
RelaxedBoundPolicy::AllowedIfOnTyParam(id, params) => {
|
||||
if let Some(res) = self.get_partial_res(id).and_then(|r| r.full_res())
|
||||
if let Some(res) = self.resolver.get_partial_res(id).and_then(|r| r.full_res())
|
||||
&& let Res::Def(DefKind::TyParam, def_id) = res
|
||||
&& params.iter().any(|p| def_id == self.local_def_id(p.id).to_def_id())
|
||||
{
|
||||
@@ -2443,7 +2512,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// We're lowering a const argument that was originally thought to be a type argument,
|
||||
// so the def collector didn't create the def ahead of time. That's why we have to do
|
||||
// it here.
|
||||
let def_id = self.create_def(node_id, None, DefKind::AnonConst, span);
|
||||
let def_id = self.create_def(
|
||||
node_id,
|
||||
None,
|
||||
DefKind::AnonConst,
|
||||
DefPathData::LateAnonConst,
|
||||
span,
|
||||
);
|
||||
let hir_id = self.lower_node_id(node_id);
|
||||
|
||||
let path_expr = Expr {
|
||||
@@ -2505,17 +2580,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let span = self.lower_span(expr.span);
|
||||
|
||||
let overly_complex_const = |this: &mut Self| {
|
||||
let msg = "complex const arguments must be placed inside of a `const` block";
|
||||
let e = if expr::WillCreateDefIdsVisitor.visit_expr(expr).is_break() {
|
||||
// FIXME(mgca): make this non-fatal once we have a better way to handle
|
||||
// nested items in const args
|
||||
// Issue: https://github.com/rust-lang/rust/issues/154539
|
||||
this.dcx().struct_span_fatal(expr.span, msg).emit()
|
||||
} else {
|
||||
this.dcx().struct_span_err(expr.span, msg).emit()
|
||||
};
|
||||
let e = this.dcx().struct_span_err(
|
||||
expr.span,
|
||||
"complex const arguments must be placed inside of a `const` block",
|
||||
);
|
||||
|
||||
ConstArg { hir_id: this.next_id(), kind: hir::ConstArgKind::Error(e), span }
|
||||
ConstArg { hir_id: this.next_id(), kind: hir::ConstArgKind::Error(e.emit()), span }
|
||||
};
|
||||
|
||||
match &expr.kind {
|
||||
@@ -2720,7 +2790,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
};
|
||||
|
||||
let maybe_res =
|
||||
self.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res());
|
||||
self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res());
|
||||
if let ExprKind::Path(qself, path) = &expr.kind
|
||||
&& path.is_potential_trivial_const_arg()
|
||||
&& matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _)))
|
||||
@@ -3032,7 +3102,10 @@ impl<'hir> GenericArgsCtor<'hir> {
|
||||
&& self.parenthesized == hir::GenericArgsParentheses::No
|
||||
}
|
||||
|
||||
fn into_generic_args(self, this: &LoweringContext<'_, 'hir>) -> &'hir hir::GenericArgs<'hir> {
|
||||
fn into_generic_args(
|
||||
self,
|
||||
this: &LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
|
||||
) -> &'hir hir::GenericArgs<'hir> {
|
||||
let ga = hir::GenericArgs {
|
||||
args: this.arena.alloc_from_iter(self.args),
|
||||
constraints: self.constraints,
|
||||
|
||||
@@ -3,6 +3,7 @@ use std::sync::Arc;
|
||||
use rustc_ast::*;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::definitions::DefPathData;
|
||||
use rustc_hir::{self as hir, LangItem, Target};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_span::{DesugaringKind, Ident, Span, Spanned, respan};
|
||||
@@ -10,11 +11,10 @@ use rustc_span::{DesugaringKind, Ident, Span, Spanned, respan};
|
||||
use super::errors::{
|
||||
ArbitraryExpressionInPattern, ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding,
|
||||
};
|
||||
use super::{
|
||||
AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode,
|
||||
};
|
||||
use super::{ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt};
|
||||
use crate::{AllowReturnTypeNotation, ImplTraitPosition};
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
pub(crate) fn lower_pat(&mut self, pattern: &Pat) -> &'hir hir::Pat<'hir> {
|
||||
self.arena.alloc(self.lower_pat_mut(pattern))
|
||||
}
|
||||
@@ -288,7 +288,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
hir_id: hir::HirId,
|
||||
lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>,
|
||||
) -> hir::PatKind<'hir> {
|
||||
match self.get_partial_res(p.id).map(|d| d.expect_full_res()) {
|
||||
match self.resolver.get_partial_res(p.id).map(|d| d.expect_full_res()) {
|
||||
// `None` can occur in body-less function signatures
|
||||
res @ (None | Some(Res::Local(_))) => {
|
||||
let binding_id = match res {
|
||||
@@ -538,7 +538,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
// We're generating a range end that didn't exist in the AST,
|
||||
// so the def collector didn't create the def ahead of time. That's why we have to do
|
||||
// it here.
|
||||
let def_id = self.create_def(node_id, None, DefKind::AnonConst, span);
|
||||
let def_id =
|
||||
self.create_def(node_id, None, DefKind::AnonConst, DefPathData::LateAnonConst, span);
|
||||
let hir_id = self.lower_node_id(node_id);
|
||||
|
||||
let unstable_span = self.mark_span_with_reason(
|
||||
|
||||
@@ -20,7 +20,7 @@ use super::{
|
||||
LifetimeRes, LoweringContext, ParamMode, ResolverAstLoweringExt,
|
||||
};
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
pub(crate) fn lower_qpath(
|
||||
&mut self,
|
||||
@@ -41,7 +41,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
self.lower_ty_alloc(&q.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path))
|
||||
});
|
||||
|
||||
let partial_res = self.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err));
|
||||
let partial_res =
|
||||
self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err));
|
||||
let base_res = partial_res.base_res();
|
||||
let unresolved_segments = partial_res.unresolved_segments();
|
||||
|
||||
|
||||
@@ -18,5 +18,5 @@ rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
thin-vec = "0.2.15"
|
||||
thin-vec = "0.2.12"
|
||||
# tidy-alphabetical-end
|
||||
|
||||
@@ -208,7 +208,7 @@ impl<'a> AstValidator<'a> {
|
||||
}
|
||||
|
||||
// Mirrors `visit::walk_ty`, but tracks relevant state.
|
||||
fn walk_ty(&mut self, t: &Ty) {
|
||||
fn walk_ty(&mut self, t: &'a Ty) {
|
||||
match &t.kind {
|
||||
TyKind::ImplTrait(_, bounds) => {
|
||||
self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t));
|
||||
@@ -731,7 +731,7 @@ impl<'a> AstValidator<'a> {
|
||||
/// C-variadics must be:
|
||||
/// - Non-const
|
||||
/// - Either foreign, or free and `unsafe extern "C"` semantically
|
||||
fn check_c_variadic_type(&self, fk: FnKind<'_>, attrs: &AttrVec) {
|
||||
fn check_c_variadic_type(&self, fk: FnKind<'a>, attrs: &'a AttrVec) {
|
||||
// `...` is already rejected when it is not the final parameter.
|
||||
let variadic_param = match fk.decl().inputs.last() {
|
||||
Some(param) if matches!(param.ty.kind, TyKind::CVarArgs) => param,
|
||||
@@ -806,7 +806,7 @@ impl<'a> AstValidator<'a> {
|
||||
fn check_c_variadic_abi(
|
||||
&self,
|
||||
abi: ExternAbi,
|
||||
attrs: &AttrVec,
|
||||
attrs: &'a AttrVec,
|
||||
dotdotdot_span: Span,
|
||||
sig: &FnSig,
|
||||
) {
|
||||
@@ -976,7 +976,7 @@ impl<'a> AstValidator<'a> {
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_ty_common(&mut self, ty: &Ty) {
|
||||
fn visit_ty_common(&mut self, ty: &'a Ty) {
|
||||
match &ty.kind {
|
||||
TyKind::FnPtr(bfty) => {
|
||||
self.check_fn_ptr_safety(bfty.decl_span, bfty.safety);
|
||||
@@ -1039,13 +1039,13 @@ impl<'a> AstValidator<'a> {
|
||||
}
|
||||
|
||||
// Used within `visit_item` for item kinds where we don't call `visit::walk_item`.
|
||||
fn visit_attrs_vis(&mut self, attrs: &AttrVec, vis: &Visibility) {
|
||||
fn visit_attrs_vis(&mut self, attrs: &'a AttrVec, vis: &'a Visibility) {
|
||||
walk_list!(self, visit_attribute, attrs);
|
||||
self.visit_vis(vis);
|
||||
}
|
||||
|
||||
// Used within `visit_item` for item kinds where we don't call `visit::walk_item`.
|
||||
fn visit_attrs_vis_ident(&mut self, attrs: &AttrVec, vis: &Visibility, ident: &Ident) {
|
||||
fn visit_attrs_vis_ident(&mut self, attrs: &'a AttrVec, vis: &'a Visibility, ident: &'a Ident) {
|
||||
walk_list!(self, visit_attribute, attrs);
|
||||
self.visit_vis(vis);
|
||||
self.visit_ident(ident);
|
||||
@@ -1125,17 +1125,17 @@ fn validate_generic_param_order(dcx: DiagCtxtHandle<'_>, generics: &[GenericPara
|
||||
}
|
||||
}
|
||||
|
||||
impl Visitor<'_> for AstValidator<'_> {
|
||||
impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
fn visit_attribute(&mut self, attr: &Attribute) {
|
||||
validate_attr::check_attr(&self.sess.psess, attr);
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, ty: &Ty) {
|
||||
fn visit_ty(&mut self, ty: &'a Ty) {
|
||||
self.visit_ty_common(ty);
|
||||
self.walk_ty(ty)
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, item: &Item) {
|
||||
fn visit_item(&mut self, item: &'a Item) {
|
||||
if item.attrs.iter().any(|attr| attr.is_proc_macro_attr()) {
|
||||
self.has_proc_macro_decls = true;
|
||||
}
|
||||
@@ -1477,7 +1477,7 @@ impl Visitor<'_> for AstValidator<'_> {
|
||||
self.lint_node_id = previous_lint_node_id;
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, fi: &ForeignItem) {
|
||||
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
|
||||
match &fi.kind {
|
||||
ForeignItemKind::Fn(box Fn { defaultness, ident, sig, body, .. }) => {
|
||||
self.check_defaultness(fi.span, *defaultness, AllowDefault::No, AllowFinal::No);
|
||||
@@ -1527,7 +1527,7 @@ impl Visitor<'_> for AstValidator<'_> {
|
||||
}
|
||||
|
||||
// Mirrors `visit::walk_generic_args`, but tracks relevant state.
|
||||
fn visit_generic_args(&mut self, generic_args: &GenericArgs) {
|
||||
fn visit_generic_args(&mut self, generic_args: &'a GenericArgs) {
|
||||
match generic_args {
|
||||
GenericArgs::AngleBracketed(data) => {
|
||||
self.check_generic_args_before_constraints(data);
|
||||
@@ -1557,7 +1557,7 @@ impl Visitor<'_> for AstValidator<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_generics(&mut self, generics: &Generics) {
|
||||
fn visit_generics(&mut self, generics: &'a Generics) {
|
||||
let mut prev_param_default = None;
|
||||
for param in &generics.params {
|
||||
match param.kind {
|
||||
@@ -1613,7 +1613,7 @@ impl Visitor<'_> for AstValidator<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_param_bound(&mut self, bound: &GenericBound, ctxt: BoundKind) {
|
||||
fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
|
||||
match bound {
|
||||
GenericBound::Trait(trait_ref) => {
|
||||
match (ctxt, trait_ref.modifiers.constness, trait_ref.modifiers.polarity) {
|
||||
@@ -1671,7 +1671,7 @@ impl Visitor<'_> for AstValidator<'_> {
|
||||
visit::walk_param_bound(self, bound)
|
||||
}
|
||||
|
||||
fn visit_fn(&mut self, fk: FnKind<'_>, attrs: &AttrVec, span: Span, id: NodeId) {
|
||||
fn visit_fn(&mut self, fk: FnKind<'a>, attrs: &AttrVec, span: Span, id: NodeId) {
|
||||
// Only associated `fn`s can have `self` parameters.
|
||||
let self_semantic = match fk.ctxt() {
|
||||
Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
|
||||
@@ -1784,7 +1784,7 @@ impl Visitor<'_> for AstValidator<'_> {
|
||||
self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
|
||||
}
|
||||
|
||||
fn visit_assoc_item(&mut self, item: &AssocItem, ctxt: AssocCtxt) {
|
||||
fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
|
||||
if let Some(ident) = item.kind.ident()
|
||||
&& attr::contains_name(&item.attrs, sym::no_mangle)
|
||||
{
|
||||
@@ -1931,7 +1931,7 @@ impl Visitor<'_> for AstValidator<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_anon_const(&mut self, anon_const: &AnonConst) {
|
||||
fn visit_anon_const(&mut self, anon_const: &'a AnonConst) {
|
||||
self.with_tilde_const(
|
||||
Some(TildeConstReason::AnonConst { span: anon_const.value.span }),
|
||||
|this| visit::walk_anon_const(this, anon_const),
|
||||
|
||||
@@ -7,7 +7,7 @@ use rustc_hir::Attribute;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::parse::{feature_err, feature_warn};
|
||||
use rustc_span::{Span, Spanned, Symbol, sym};
|
||||
use rustc_span::{DUMMY_SP, Span, Spanned, Symbol, sym};
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
use crate::errors;
|
||||
@@ -646,7 +646,14 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate)
|
||||
let mut errored = false;
|
||||
|
||||
if let Some(Attribute::Parsed(AttributeKind::Feature(feature_idents, first_span))) =
|
||||
AttributeParser::parse_limited(sess, &krate.attrs, &[sym::feature])
|
||||
AttributeParser::parse_limited(
|
||||
sess,
|
||||
&krate.attrs,
|
||||
&[sym::feature],
|
||||
DUMMY_SP,
|
||||
krate.id,
|
||||
Some(&features),
|
||||
)
|
||||
{
|
||||
// `feature(...)` used on non-nightly. This is definitely an error.
|
||||
let mut err = errors::FeatureOnNonNightly {
|
||||
|
||||
@@ -13,5 +13,5 @@ rustc_span = { path = "../rustc_span" }
|
||||
|
||||
[dev-dependencies]
|
||||
# tidy-alphabetical-start
|
||||
thin-vec = "0.2.15"
|
||||
thin-vec = "0.2.12"
|
||||
# tidy-alphabetical-end
|
||||
|
||||
49
compiler/rustc_ast_pretty/src/helpers.rs
Normal file
49
compiler/rustc_ast_pretty/src/helpers.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use crate::pp::Printer;
|
||||
|
||||
impl Printer {
|
||||
pub fn word_space<W: Into<Cow<'static, str>>>(&mut self, w: W) {
|
||||
self.word(w);
|
||||
self.space();
|
||||
}
|
||||
|
||||
pub fn popen(&mut self) {
|
||||
self.word("(");
|
||||
}
|
||||
|
||||
pub fn pclose(&mut self) {
|
||||
self.word(")");
|
||||
}
|
||||
|
||||
pub fn hardbreak_if_not_bol(&mut self) {
|
||||
if !self.is_beginning_of_line() {
|
||||
self.hardbreak()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn space_if_not_bol(&mut self) {
|
||||
if !self.is_beginning_of_line() {
|
||||
self.space();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn nbsp(&mut self) {
|
||||
self.word(" ")
|
||||
}
|
||||
|
||||
pub fn word_nbsp<S: Into<Cow<'static, str>>>(&mut self, w: S) {
|
||||
self.word(w);
|
||||
self.nbsp()
|
||||
}
|
||||
|
||||
/// Synthesizes a comment that was not textually present in the original
|
||||
/// source file.
|
||||
pub fn synth_comment(&mut self, text: impl Into<Cow<'static, str>>) {
|
||||
self.word("/*");
|
||||
self.space();
|
||||
self.word(text);
|
||||
self.space();
|
||||
self.word("*/")
|
||||
}
|
||||
}
|
||||
@@ -3,5 +3,6 @@
|
||||
#![feature(negative_impls)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
mod helpers;
|
||||
pub mod pp;
|
||||
pub mod pprust;
|
||||
|
||||
@@ -132,6 +132,7 @@
|
||||
//! methods called `Printer::scan_*`, and the 'PRINT' process is the
|
||||
//! method called `Printer::print`.
|
||||
|
||||
mod convenience;
|
||||
mod ring;
|
||||
|
||||
use std::borrow::Cow;
|
||||
@@ -187,12 +188,6 @@ pub(crate) enum Token {
|
||||
End,
|
||||
}
|
||||
|
||||
impl Token {
|
||||
pub(crate) fn is_hardbreak_tok(&self) -> bool {
|
||||
*self == Printer::hardbreak_tok_offset(0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum PrintFrame {
|
||||
Fits,
|
||||
@@ -484,132 +479,4 @@ impl Printer {
|
||||
self.out.push_str(string);
|
||||
self.space -= string.len() as isize;
|
||||
}
|
||||
|
||||
/// Synthesizes a comment that was not textually present in the original
|
||||
/// source file.
|
||||
pub fn synth_comment(&mut self, text: impl Into<Cow<'static, str>>) {
|
||||
self.word("/*");
|
||||
self.space();
|
||||
self.word(text);
|
||||
self.space();
|
||||
self.word("*/")
|
||||
}
|
||||
|
||||
/// "raw box"
|
||||
pub fn rbox(&mut self, indent: isize, breaks: Breaks) -> BoxMarker {
|
||||
self.scan_begin(BeginToken { indent: IndentStyle::Block { offset: indent }, breaks })
|
||||
}
|
||||
|
||||
/// Inconsistent breaking box
|
||||
pub fn ibox(&mut self, indent: isize) -> BoxMarker {
|
||||
self.rbox(indent, Breaks::Inconsistent)
|
||||
}
|
||||
|
||||
/// Consistent breaking box
|
||||
pub fn cbox(&mut self, indent: isize) -> BoxMarker {
|
||||
self.rbox(indent, Breaks::Consistent)
|
||||
}
|
||||
|
||||
pub fn visual_align(&mut self) -> BoxMarker {
|
||||
self.scan_begin(BeginToken { indent: IndentStyle::Visual, breaks: Breaks::Consistent })
|
||||
}
|
||||
|
||||
pub fn break_offset(&mut self, n: usize, off: isize) {
|
||||
self.scan_break(BreakToken {
|
||||
offset: off,
|
||||
blank_space: n as isize,
|
||||
..BreakToken::default()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn end(&mut self, b: BoxMarker) {
|
||||
self.scan_end(b)
|
||||
}
|
||||
|
||||
pub fn eof(mut self) -> String {
|
||||
self.scan_eof();
|
||||
self.out
|
||||
}
|
||||
|
||||
pub fn word<S: Into<Cow<'static, str>>>(&mut self, wrd: S) {
|
||||
let string = wrd.into();
|
||||
self.scan_string(string)
|
||||
}
|
||||
|
||||
pub fn word_space<W: Into<Cow<'static, str>>>(&mut self, w: W) {
|
||||
self.word(w);
|
||||
self.space();
|
||||
}
|
||||
|
||||
pub fn nbsp(&mut self) {
|
||||
self.word(" ")
|
||||
}
|
||||
|
||||
pub fn word_nbsp<S: Into<Cow<'static, str>>>(&mut self, w: S) {
|
||||
self.word(w);
|
||||
self.nbsp()
|
||||
}
|
||||
|
||||
fn spaces(&mut self, n: usize) {
|
||||
self.break_offset(n, 0)
|
||||
}
|
||||
|
||||
pub fn zerobreak(&mut self) {
|
||||
self.spaces(0)
|
||||
}
|
||||
|
||||
pub fn space(&mut self) {
|
||||
self.spaces(1)
|
||||
}
|
||||
|
||||
pub fn popen(&mut self) {
|
||||
self.word("(");
|
||||
}
|
||||
|
||||
pub fn pclose(&mut self) {
|
||||
self.word(")");
|
||||
}
|
||||
|
||||
pub fn hardbreak(&mut self) {
|
||||
self.spaces(SIZE_INFINITY as usize)
|
||||
}
|
||||
|
||||
pub fn is_beginning_of_line(&self) -> bool {
|
||||
match self.last_token() {
|
||||
Some(last_token) => last_token.is_hardbreak_tok(),
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hardbreak_if_not_bol(&mut self) {
|
||||
if !self.is_beginning_of_line() {
|
||||
self.hardbreak()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn space_if_not_bol(&mut self) {
|
||||
if !self.is_beginning_of_line() {
|
||||
self.space();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn hardbreak_tok_offset(off: isize) -> Token {
|
||||
Token::Break(BreakToken {
|
||||
offset: off,
|
||||
blank_space: SIZE_INFINITY,
|
||||
..BreakToken::default()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn trailing_comma(&mut self) {
|
||||
self.scan_break(BreakToken { pre_break: Some(','), ..BreakToken::default() });
|
||||
}
|
||||
|
||||
pub fn trailing_comma_or_space(&mut self) {
|
||||
self.scan_break(BreakToken {
|
||||
blank_space: 1,
|
||||
pre_break: Some(','),
|
||||
..BreakToken::default()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
97
compiler/rustc_ast_pretty/src/pp/convenience.rs
Normal file
97
compiler/rustc_ast_pretty/src/pp/convenience.rs
Normal file
@@ -0,0 +1,97 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use crate::pp::{
|
||||
BeginToken, BoxMarker, BreakToken, Breaks, IndentStyle, Printer, SIZE_INFINITY, Token,
|
||||
};
|
||||
|
||||
impl Printer {
|
||||
/// "raw box"
|
||||
pub fn rbox(&mut self, indent: isize, breaks: Breaks) -> BoxMarker {
|
||||
self.scan_begin(BeginToken { indent: IndentStyle::Block { offset: indent }, breaks })
|
||||
}
|
||||
|
||||
/// Inconsistent breaking box
|
||||
pub fn ibox(&mut self, indent: isize) -> BoxMarker {
|
||||
self.rbox(indent, Breaks::Inconsistent)
|
||||
}
|
||||
|
||||
/// Consistent breaking box
|
||||
pub fn cbox(&mut self, indent: isize) -> BoxMarker {
|
||||
self.rbox(indent, Breaks::Consistent)
|
||||
}
|
||||
|
||||
pub fn visual_align(&mut self) -> BoxMarker {
|
||||
self.scan_begin(BeginToken { indent: IndentStyle::Visual, breaks: Breaks::Consistent })
|
||||
}
|
||||
|
||||
pub fn break_offset(&mut self, n: usize, off: isize) {
|
||||
self.scan_break(BreakToken {
|
||||
offset: off,
|
||||
blank_space: n as isize,
|
||||
..BreakToken::default()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn end(&mut self, b: BoxMarker) {
|
||||
self.scan_end(b)
|
||||
}
|
||||
|
||||
pub fn eof(mut self) -> String {
|
||||
self.scan_eof();
|
||||
self.out
|
||||
}
|
||||
|
||||
pub fn word<S: Into<Cow<'static, str>>>(&mut self, wrd: S) {
|
||||
let string = wrd.into();
|
||||
self.scan_string(string)
|
||||
}
|
||||
|
||||
fn spaces(&mut self, n: usize) {
|
||||
self.break_offset(n, 0)
|
||||
}
|
||||
|
||||
pub fn zerobreak(&mut self) {
|
||||
self.spaces(0)
|
||||
}
|
||||
|
||||
pub fn space(&mut self) {
|
||||
self.spaces(1)
|
||||
}
|
||||
|
||||
pub fn hardbreak(&mut self) {
|
||||
self.spaces(SIZE_INFINITY as usize)
|
||||
}
|
||||
|
||||
pub fn is_beginning_of_line(&self) -> bool {
|
||||
match self.last_token() {
|
||||
Some(last_token) => last_token.is_hardbreak_tok(),
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn hardbreak_tok_offset(off: isize) -> Token {
|
||||
Token::Break(BreakToken {
|
||||
offset: off,
|
||||
blank_space: SIZE_INFINITY,
|
||||
..BreakToken::default()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn trailing_comma(&mut self) {
|
||||
self.scan_break(BreakToken { pre_break: Some(','), ..BreakToken::default() });
|
||||
}
|
||||
|
||||
pub fn trailing_comma_or_space(&mut self) {
|
||||
self.scan_break(BreakToken {
|
||||
blank_space: 1,
|
||||
pre_break: Some(','),
|
||||
..BreakToken::default()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Token {
|
||||
pub(crate) fn is_hardbreak_tok(&self) -> bool {
|
||||
*self == Printer::hardbreak_tok_offset(0)
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,6 @@ impl<'a> State<'a> {
|
||||
expr,
|
||||
safety,
|
||||
define_opaque,
|
||||
eii_impls,
|
||||
}) => self.print_item_const(
|
||||
*ident,
|
||||
Some(*mutability),
|
||||
@@ -54,7 +53,6 @@ impl<'a> State<'a> {
|
||||
*safety,
|
||||
ast::Defaultness::Implicit,
|
||||
define_opaque.as_deref(),
|
||||
eii_impls,
|
||||
),
|
||||
ast::ForeignItemKind::TyAlias(box ast::TyAlias {
|
||||
defaultness,
|
||||
@@ -95,12 +93,8 @@ impl<'a> State<'a> {
|
||||
safety: ast::Safety,
|
||||
defaultness: ast::Defaultness,
|
||||
define_opaque: Option<&[(ast::NodeId, ast::Path)]>,
|
||||
eii_impls: &[EiiImpl],
|
||||
) {
|
||||
self.print_define_opaques(define_opaque);
|
||||
for eii_impl in eii_impls {
|
||||
self.print_eii_impl(eii_impl);
|
||||
}
|
||||
let (cb, ib) = self.head("");
|
||||
self.print_visibility(vis);
|
||||
self.print_safety(safety);
|
||||
@@ -197,7 +191,6 @@ impl<'a> State<'a> {
|
||||
mutability: mutbl,
|
||||
expr: body,
|
||||
define_opaque,
|
||||
eii_impls,
|
||||
}) => {
|
||||
self.print_safety(*safety);
|
||||
self.print_item_const(
|
||||
@@ -210,7 +203,6 @@ impl<'a> State<'a> {
|
||||
ast::Safety::Default,
|
||||
ast::Defaultness::Implicit,
|
||||
define_opaque.as_deref(),
|
||||
eii_impls,
|
||||
);
|
||||
}
|
||||
ast::ItemKind::ConstBlock(ast::ConstBlockItem { id: _, span: _, block }) => {
|
||||
@@ -242,7 +234,6 @@ impl<'a> State<'a> {
|
||||
ast::Safety::Default,
|
||||
*defaultness,
|
||||
define_opaque.as_deref(),
|
||||
&[],
|
||||
);
|
||||
}
|
||||
ast::ItemKind::Fn(func) => {
|
||||
@@ -371,10 +362,10 @@ impl<'a> State<'a> {
|
||||
self.bclose(item.span, empty, cb);
|
||||
}
|
||||
ast::ItemKind::Trait(box ast::Trait {
|
||||
impl_restriction,
|
||||
constness,
|
||||
safety,
|
||||
is_auto,
|
||||
impl_restriction,
|
||||
ident,
|
||||
generics,
|
||||
bounds,
|
||||
@@ -382,10 +373,10 @@ impl<'a> State<'a> {
|
||||
}) => {
|
||||
let (cb, ib) = self.head("");
|
||||
self.print_visibility(&item.vis);
|
||||
self.print_impl_restriction(impl_restriction);
|
||||
self.print_constness(*constness);
|
||||
self.print_safety(*safety);
|
||||
self.print_is_auto(*is_auto);
|
||||
self.print_impl_restriction(impl_restriction);
|
||||
self.word_nbsp("trait");
|
||||
self.print_ident(*ident);
|
||||
self.print_generic_params(&generics.params);
|
||||
@@ -444,10 +435,7 @@ impl<'a> State<'a> {
|
||||
&item.vis,
|
||||
&deleg.qself,
|
||||
&deleg.prefix,
|
||||
match &deleg.suffixes {
|
||||
ast::DelegationSuffixes::List(s) => DelegationKind::List(s),
|
||||
ast::DelegationSuffixes::Glob(_) => DelegationKind::Glob,
|
||||
},
|
||||
deleg.suffixes.as_ref().map_or(DelegationKind::Glob, |s| DelegationKind::List(s)),
|
||||
&deleg.body,
|
||||
),
|
||||
}
|
||||
@@ -614,7 +602,6 @@ impl<'a> State<'a> {
|
||||
ast::Safety::Default,
|
||||
*defaultness,
|
||||
define_opaque.as_deref(),
|
||||
&[],
|
||||
);
|
||||
}
|
||||
ast::AssocItemKind::Type(box ast::TyAlias {
|
||||
@@ -654,10 +641,7 @@ impl<'a> State<'a> {
|
||||
vis,
|
||||
&deleg.qself,
|
||||
&deleg.prefix,
|
||||
match &deleg.suffixes {
|
||||
ast::DelegationSuffixes::List(s) => DelegationKind::List(s),
|
||||
ast::DelegationSuffixes::Glob(_) => DelegationKind::Glob,
|
||||
},
|
||||
deleg.suffixes.as_ref().map_or(DelegationKind::Glob, |s| DelegationKind::List(s)),
|
||||
&deleg.body,
|
||||
),
|
||||
}
|
||||
@@ -719,8 +703,18 @@ impl<'a> State<'a> {
|
||||
|
||||
self.print_define_opaques(define_opaque.as_deref());
|
||||
|
||||
for eii_impl in eii_impls {
|
||||
self.print_eii_impl(eii_impl);
|
||||
for EiiImpl { eii_macro_path, impl_safety, .. } in eii_impls {
|
||||
self.word("#[");
|
||||
if let Safety::Unsafe(..) = impl_safety {
|
||||
self.word("unsafe");
|
||||
self.popen();
|
||||
}
|
||||
self.print_path(eii_macro_path, false, 0);
|
||||
if let Safety::Unsafe(..) = impl_safety {
|
||||
self.pclose();
|
||||
}
|
||||
self.word("]");
|
||||
self.hardbreak();
|
||||
}
|
||||
|
||||
let body_cb_ib = body.as_ref().map(|body| (body, self.head("")));
|
||||
@@ -747,20 +741,6 @@ impl<'a> State<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn print_eii_impl(&mut self, eii: &ast::EiiImpl) {
|
||||
self.word("#[");
|
||||
if let Safety::Unsafe(..) = eii.impl_safety {
|
||||
self.word("unsafe");
|
||||
self.popen();
|
||||
}
|
||||
self.print_path(&eii.eii_macro_path, false, 0);
|
||||
if let Safety::Unsafe(..) = eii.impl_safety {
|
||||
self.pclose();
|
||||
}
|
||||
self.word("]");
|
||||
self.hardbreak();
|
||||
}
|
||||
|
||||
fn print_define_opaques(&mut self, define_opaque: Option<&[(ast::NodeId, ast::Path)]>) {
|
||||
if let Some(define_opaque) = define_opaque {
|
||||
self.word("#[define_opaque(");
|
||||
|
||||
@@ -19,5 +19,5 @@ rustc_parse_format = { path = "../rustc_parse_format" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
thin-vec = "0.2.15"
|
||||
thin-vec = "0.2.12"
|
||||
# tidy-alphabetical-end
|
||||
|
||||
@@ -81,7 +81,7 @@ fn parse_unstable<S: Stage>(
|
||||
) -> impl IntoIterator<Item = Symbol> {
|
||||
let mut res = Vec::new();
|
||||
|
||||
let Some(list) = args.as_list() else {
|
||||
let Some(list) = args.list() else {
|
||||
cx.emit_err(session_diagnostics::ExpectsFeatureList {
|
||||
span: cx.attr_span,
|
||||
name: symbol.to_ident_string(),
|
||||
|
||||
@@ -8,8 +8,8 @@ use rustc_hir::{MethodKind, Target};
|
||||
use rustc_span::{Symbol, sym};
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
use crate::attributes::SingleAttributeParser;
|
||||
use crate::attributes::prelude::Allow;
|
||||
use crate::attributes::{OnDuplicate, SingleAttributeParser};
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::parser::{ArgParser, MetaItemOrLitParser};
|
||||
use crate::target_checking::AllowedTargets;
|
||||
@@ -18,6 +18,7 @@ pub(crate) struct RustcAutodiffParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcAutodiffParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_autodiff];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
|
||||
@@ -6,6 +6,7 @@ pub(crate) struct CoroutineParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for CoroutineParser {
|
||||
const PATH: &[Symbol] = &[sym::coroutine];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Closure)]);
|
||||
const CREATE: fn(rustc_span::Span) -> AttributeKind = |span| AttributeKind::Coroutine(span);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::convert::identity;
|
||||
|
||||
use rustc_ast::token::Delimiter;
|
||||
use rustc_ast::tokenstream::DelimSpan;
|
||||
use rustc_ast::{AttrItem, Attribute, LitKind, ast, token};
|
||||
use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, ast, token};
|
||||
use rustc_errors::{Applicability, PResult, msg};
|
||||
use rustc_feature::{
|
||||
AttrSuggestionStyle, AttributeTemplate, Features, GatedCfg, find_gated_cfg, template,
|
||||
@@ -19,7 +19,6 @@ use rustc_session::parse::{ParseSess, feature_err};
|
||||
use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
use crate::attributes::AttributeSafety;
|
||||
use crate::context::{AcceptContext, ShouldEmit, Stage};
|
||||
use crate::parser::{
|
||||
AllowExprMetavar, ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser,
|
||||
@@ -44,9 +43,13 @@ pub fn parse_cfg<S: Stage>(
|
||||
cx: &mut AcceptContext<'_, '_, S>,
|
||||
args: &ArgParser,
|
||||
) -> Option<CfgEntry> {
|
||||
let list = cx.expect_list(args, cx.attr_span)?;
|
||||
let ArgParser::List(list) = args else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_list(attr_span, args);
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(single) = list.as_single() else {
|
||||
let Some(single) = list.single() else {
|
||||
let target = cx.target;
|
||||
let mut adcx = cx.adcx();
|
||||
if list.is_empty() {
|
||||
@@ -75,7 +78,7 @@ pub fn parse_cfg<S: Stage>(
|
||||
}
|
||||
}
|
||||
|
||||
adcx.expected_single_argument(list.span, list.len());
|
||||
adcx.expected_single_argument(list.span);
|
||||
return None;
|
||||
};
|
||||
parse_cfg_entry(cx, single).ok()
|
||||
@@ -89,8 +92,8 @@ pub fn parse_cfg_entry<S: Stage>(
|
||||
MetaItemOrLitParser::MetaItemParser(meta) => match meta.args() {
|
||||
ArgParser::List(list) => match meta.path().word_sym() {
|
||||
Some(sym::not) => {
|
||||
let Some(single) = list.as_single() else {
|
||||
return Err(cx.adcx().expected_single_argument(list.span, list.len()));
|
||||
let Some(single) = list.single() else {
|
||||
return Err(cx.adcx().expected_single_argument(list.span));
|
||||
};
|
||||
CfgEntry::Not(Box::new(parse_cfg_entry(cx, single)?), list.span)
|
||||
}
|
||||
@@ -132,7 +135,7 @@ fn parse_cfg_entry_version<S: Stage>(
|
||||
meta_span: Span,
|
||||
) -> Result<CfgEntry, ErrorGuaranteed> {
|
||||
try_gate_cfg(sym::version, meta_span, cx.sess(), cx.features_option());
|
||||
let Some(version) = list.as_single() else {
|
||||
let Some(version) = list.single() else {
|
||||
return Err(
|
||||
cx.emit_err(session_diagnostics::ExpectedSingleVersionLiteral { span: list.span })
|
||||
);
|
||||
@@ -321,13 +324,12 @@ pub fn parse_cfg_attr(
|
||||
cfg_attr: &Attribute,
|
||||
sess: &Session,
|
||||
features: Option<&Features>,
|
||||
lint_node_id: ast::NodeId,
|
||||
) -> Option<(CfgEntry, Vec<(AttrItem, Span)>)> {
|
||||
match cfg_attr.get_normal_item().args.unparsed_ref().unwrap() {
|
||||
ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, tokens }) if !tokens.is_empty() => {
|
||||
check_cfg_attr_bad_delim(&sess.psess, *dspan, *delim);
|
||||
match parse_in(&sess.psess, tokens.clone(), "`cfg_attr` input", |p| {
|
||||
parse_cfg_attr_internal(p, sess, features, lint_node_id, cfg_attr)
|
||||
parse_cfg_attr_internal(p, sess, features, cfg_attr)
|
||||
}) {
|
||||
Ok(r) => return Some(r),
|
||||
Err(e) => {
|
||||
@@ -388,7 +390,6 @@ fn parse_cfg_attr_internal<'a>(
|
||||
parser: &mut Parser<'a>,
|
||||
sess: &'a Session,
|
||||
features: Option<&Features>,
|
||||
lint_node_id: ast::NodeId,
|
||||
attribute: &Attribute,
|
||||
) -> PResult<'a, (CfgEntry, Vec<(ast::AttrItem, Span)>)> {
|
||||
// Parse cfg predicate
|
||||
@@ -407,10 +408,9 @@ fn parse_cfg_attr_internal<'a>(
|
||||
attribute.style,
|
||||
AttrPath { segments: attribute.path().into_boxed_slice(), span: attribute.span },
|
||||
Some(attribute.get_normal_item().unsafety),
|
||||
AttributeSafety::Normal,
|
||||
ParsedDescription::Attribute,
|
||||
pred_span,
|
||||
lint_node_id,
|
||||
CRATE_NODE_ID,
|
||||
Target::Crate,
|
||||
features,
|
||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
|
||||
|
||||
@@ -12,7 +12,6 @@ use rustc_session::Session;
|
||||
use rustc_session::lint::builtin::UNREACHABLE_CFG_SELECT_PREDICATES;
|
||||
use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
|
||||
|
||||
use crate::attributes::AttributeSafety;
|
||||
use crate::parser::{AllowExprMetavar, MetaItemOrLitParser};
|
||||
use crate::{AttributeParser, ParsedDescription, ShouldEmit, errors, parse_cfg_entry};
|
||||
|
||||
@@ -106,7 +105,6 @@ pub fn parse_cfg_select(
|
||||
AttrStyle::Inner,
|
||||
AttrPath { segments: vec![sym::cfg_select].into_boxed_slice(), span: cfg_span },
|
||||
None,
|
||||
AttributeSafety::Normal,
|
||||
ParsedDescription::Macro,
|
||||
cfg_span,
|
||||
lint_node_id,
|
||||
|
||||
@@ -8,6 +8,7 @@ impl<S: Stage> SingleAttributeParser<S> for CfiEncodingParser {
|
||||
Allow(Target::Enum),
|
||||
Allow(Target::Union),
|
||||
]);
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "encoding");
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, RtsanSetting, SanitizerSet, UsedBy};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::edition::Edition::Edition2024;
|
||||
|
||||
use super::prelude::*;
|
||||
use crate::attributes::AttributeSafety;
|
||||
use crate::session_diagnostics::{
|
||||
NakedFunctionIncompatibleAttribute, NullOnExport, NullOnObjcClass, NullOnObjcSelector,
|
||||
ObjcClassExpectedStringLiteral, ObjcSelectorExpectedStringLiteral,
|
||||
@@ -14,6 +12,7 @@ pub(crate) struct OptimizeParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for OptimizeParser {
|
||||
const PATH: &[Symbol] = &[sym::optimize];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Closure),
|
||||
@@ -24,7 +23,16 @@ impl<S: Stage> SingleAttributeParser<S> for OptimizeParser {
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["size", "speed", "none"]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let single = cx.expect_single_element_list(args, cx.attr_span)?;
|
||||
let Some(list) = args.list() else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_list(attr_span, args);
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(single) = list.single() else {
|
||||
cx.adcx().expected_single_argument(list.span);
|
||||
return None;
|
||||
};
|
||||
|
||||
let res = match single.meta_item().and_then(|i| i.path().word().map(|i| i.name)) {
|
||||
Some(sym::size) => OptimizeAttr::Size,
|
||||
@@ -61,6 +69,7 @@ pub(crate) struct CoverageParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for CoverageParser {
|
||||
const PATH: &[Symbol] = &[sym::coverage];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Closure),
|
||||
@@ -75,13 +84,22 @@ impl<S: Stage> SingleAttributeParser<S> for CoverageParser {
|
||||
const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::off, sym::on]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let arg = cx.expect_single_element_list(args, cx.attr_span)?;
|
||||
let Some(args) = args.list() else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_specific_argument_and_list(attr_span, &[sym::on, sym::off]);
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(arg) = args.single() else {
|
||||
cx.adcx().expected_single_argument(args.span);
|
||||
return None;
|
||||
};
|
||||
|
||||
let mut fail_incorrect_argument =
|
||||
|span| cx.adcx().expected_specific_argument(span, &[sym::on, sym::off]);
|
||||
|
||||
let Some(arg) = arg.meta_item() else {
|
||||
fail_incorrect_argument(arg.span());
|
||||
fail_incorrect_argument(args.span);
|
||||
return None;
|
||||
};
|
||||
|
||||
@@ -103,7 +121,6 @@ pub(crate) struct ExportNameParser;
|
||||
impl<S: Stage> SingleAttributeParser<S> for ExportNameParser {
|
||||
const PATH: &[rustc_span::Symbol] = &[sym::export_name];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Static),
|
||||
Allow(Target::Fn),
|
||||
@@ -141,6 +158,7 @@ pub(crate) struct RustcObjcClassParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcObjcClassParser {
|
||||
const PATH: &[rustc_span::Symbol] = &[sym::rustc_objc_class];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets =
|
||||
AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "ClassName");
|
||||
@@ -172,6 +190,7 @@ pub(crate) struct RustcObjcSelectorParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcObjcSelectorParser {
|
||||
const PATH: &[rustc_span::Symbol] = &[sym::rustc_objc_selector];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets =
|
||||
AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "methodName");
|
||||
@@ -219,7 +238,6 @@ impl<S: Stage> AttributeParser<S> for NakedParser {
|
||||
this.span = Some(cx.attr_span);
|
||||
}
|
||||
})];
|
||||
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
@@ -340,7 +358,6 @@ pub(crate) struct NoMangleParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for NoMangleParser {
|
||||
const PATH: &[Symbol] = &[sym::no_mangle];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Static),
|
||||
@@ -371,7 +388,8 @@ impl<S: Stage> AttributeParser<S> for UsedParser {
|
||||
let used_by = match args {
|
||||
ArgParser::NoArgs => UsedBy::Default,
|
||||
ArgParser::List(list) => {
|
||||
let Some(l) = cx.expect_single(list) else {
|
||||
let Some(l) = list.single() else {
|
||||
cx.adcx().expected_single_argument(list.span);
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -462,7 +480,9 @@ fn parse_tf_attribute<S: Stage>(
|
||||
args: &ArgParser,
|
||||
) -> impl IntoIterator<Item = (Symbol, Span)> {
|
||||
let mut features = Vec::new();
|
||||
let Some(list) = cx.expect_list(args, cx.attr_span) else {
|
||||
let ArgParser::List(list) = args else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_list(attr_span, args);
|
||||
return features;
|
||||
};
|
||||
if list.is_empty() {
|
||||
@@ -540,7 +560,6 @@ pub(crate) struct ForceTargetFeatureParser;
|
||||
impl<S: Stage> CombineAttributeParser<S> for ForceTargetFeatureParser {
|
||||
type Item = (Symbol, Span);
|
||||
const PATH: &[Symbol] = &[sym::force_target_feature];
|
||||
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
|
||||
const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature {
|
||||
features: items,
|
||||
attr_span: span,
|
||||
@@ -584,8 +603,14 @@ impl<S: Stage> SingleAttributeParser<S> for SanitizeParser {
|
||||
r#"realtime = "nonblocking|blocking|caller""#,
|
||||
]);
|
||||
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let list = cx.expect_list(args, cx.attr_span)?;
|
||||
let Some(list) = args.list() else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_list(attr_span, args);
|
||||
return None;
|
||||
};
|
||||
|
||||
let mut on_set = SanitizerSet::empty();
|
||||
let mut off_set = SanitizerSet::empty();
|
||||
@@ -682,6 +707,7 @@ pub(crate) struct ThreadLocalParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for ThreadLocalParser {
|
||||
const PATH: &[Symbol] = &[sym::thread_local];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const ALLOWED_TARGETS: AllowedTargets =
|
||||
AllowedTargets::AllowList(&[Allow(Target::Static), Allow(Target::ForeignStatic)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ThreadLocal;
|
||||
@@ -691,6 +717,7 @@ pub(crate) struct RustcPassIndirectlyInNonRusticAbisParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcPassIndirectlyInNonRusticAbisParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_pass_indirectly_in_non_rustic_abis];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassIndirectlyInNonRusticAbis;
|
||||
}
|
||||
@@ -699,8 +726,8 @@ pub(crate) struct RustcEiiForeignItemParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcEiiForeignItemParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_eii_foreign_item];
|
||||
const ALLOWED_TARGETS: AllowedTargets =
|
||||
AllowedTargets::AllowList(&[Allow(Target::ForeignFn), Allow(Target::ForeignStatic)]);
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEiiForeignItem;
|
||||
}
|
||||
|
||||
@@ -708,17 +735,22 @@ pub(crate) struct PatchableFunctionEntryParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for PatchableFunctionEntryParser {
|
||||
const PATH: &[Symbol] = &[sym::patchable_function_entry];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["prefix_nops = m, entry_nops = n"]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let meta_item_list = cx.expect_list(args, cx.attr_span)?;
|
||||
let Some(meta_item_list) = args.list() else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_list(attr_span, args);
|
||||
return None;
|
||||
};
|
||||
|
||||
let mut prefix = None;
|
||||
let mut entry = None;
|
||||
|
||||
if meta_item_list.len() == 0 {
|
||||
cx.adcx().expected_at_least_one_argument(meta_item_list.span);
|
||||
cx.adcx().expected_list(meta_item_list.span, args);
|
||||
return None;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,11 @@ impl<S: Stage> AttributeParser<S> for ConfusablesParser {
|
||||
&[sym::rustc_confusables],
|
||||
template!(List: &[r#""name1", "name2", ..."#]),
|
||||
|this, cx, args| {
|
||||
let Some(list) = cx.expect_list(args, cx.attr_span) else { return };
|
||||
let Some(list) = args.list() else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_list(attr_span, args);
|
||||
return;
|
||||
};
|
||||
|
||||
if list.is_empty() {
|
||||
cx.emit_err(EmptyConfusables { span: cx.attr_span });
|
||||
@@ -40,6 +44,9 @@ impl<S: Stage> AttributeParser<S> for ConfusablesParser {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(AttributeKind::RustcConfusables { confusables: self.confusables })
|
||||
Some(AttributeKind::RustcConfusables {
|
||||
symbols: self.confusables,
|
||||
first_span: self.first_span.unwrap(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_hir::attrs::{CrateType, WindowsSubsystemKind};
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_session::lint::builtin::UNKNOWN_CRATE_TYPES;
|
||||
use rustc_span::Symbol;
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
|
||||
use super::prelude::*;
|
||||
use crate::errors::{UnknownCrateTypes, UnknownCrateTypesSuggestion};
|
||||
|
||||
pub(crate) struct CrateNameParser;
|
||||
|
||||
@@ -66,17 +65,13 @@ impl<S: Stage> CombineAttributeParser<S> for CrateTypeParser {
|
||||
crate_type,
|
||||
None,
|
||||
);
|
||||
let span = n.value_span;
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
UNKNOWN_CRATE_TYPES,
|
||||
move |dcx, level| {
|
||||
UnknownCrateTypes {
|
||||
sugg: candidate
|
||||
.map(|s| UnknownCrateTypesSuggestion { span, snippet: s }),
|
||||
}
|
||||
.into_diag(dcx, level)
|
||||
AttributeLintKind::CrateTypeUnknown {
|
||||
span: n.value_span,
|
||||
suggested: candidate,
|
||||
},
|
||||
span,
|
||||
n.value_span,
|
||||
);
|
||||
}
|
||||
return None;
|
||||
@@ -113,6 +108,7 @@ pub(crate) struct MoveSizeLimitParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for MoveSizeLimitParser {
|
||||
const PATH: &[Symbol] = &[sym::move_size_limit];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
|
||||
@@ -158,6 +154,7 @@ pub(crate) struct PatternComplexityLimitParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for PatternComplexityLimitParser {
|
||||
const PATH: &[Symbol] = &[sym::pattern_complexity_limit];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
|
||||
@@ -180,6 +177,7 @@ pub(crate) struct NoCoreParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for NoCoreParser {
|
||||
const PATH: &[Symbol] = &[sym::no_core];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoCore;
|
||||
}
|
||||
@@ -206,6 +204,7 @@ pub(crate) struct RustcCoherenceIsCoreParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcCoherenceIsCoreParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_coherence_is_core];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcCoherenceIsCore;
|
||||
}
|
||||
@@ -248,6 +247,7 @@ pub(crate) struct PanicRuntimeParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for PanicRuntimeParser {
|
||||
const PATH: &[Symbol] = &[sym::panic_runtime];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::PanicRuntime;
|
||||
}
|
||||
@@ -256,6 +256,7 @@ pub(crate) struct NeedsPanicRuntimeParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for NeedsPanicRuntimeParser {
|
||||
const PATH: &[Symbol] = &[sym::needs_panic_runtime];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsPanicRuntime;
|
||||
}
|
||||
@@ -264,6 +265,7 @@ pub(crate) struct ProfilerRuntimeParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for ProfilerRuntimeParser {
|
||||
const PATH: &[Symbol] = &[sym::profiler_runtime];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ProfilerRuntime;
|
||||
}
|
||||
@@ -281,6 +283,7 @@ 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;
|
||||
}
|
||||
@@ -289,6 +292,7 @@ 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;
|
||||
}
|
||||
@@ -297,6 +301,7 @@ pub(crate) struct DefaultLibAllocatorParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for DefaultLibAllocatorParser {
|
||||
const PATH: &[Symbol] = &[sym::default_lib_allocator];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::DefaultLibAllocator;
|
||||
}
|
||||
@@ -314,7 +319,9 @@ impl<S: Stage> CombineAttributeParser<S> for FeatureParser {
|
||||
cx: &mut AcceptContext<'_, '_, S>,
|
||||
args: &ArgParser,
|
||||
) -> impl IntoIterator<Item = Self::Item> {
|
||||
let Some(list) = cx.expect_list(args, cx.attr_span) else {
|
||||
let ArgParser::List(list) = args else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_list(attr_span, args);
|
||||
return Vec::new();
|
||||
};
|
||||
|
||||
@@ -360,7 +367,9 @@ impl<S: Stage> CombineAttributeParser<S> for RegisterToolParser {
|
||||
cx: &mut AcceptContext<'_, '_, S>,
|
||||
args: &ArgParser,
|
||||
) -> impl IntoIterator<Item = Self::Item> {
|
||||
let Some(list) = cx.expect_list(args, cx.attr_span) else {
|
||||
let ArgParser::List(list) = args else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_list(attr_span, args);
|
||||
return Vec::new();
|
||||
};
|
||||
|
||||
|
||||
@@ -20,7 +20,15 @@ impl<S: Stage> CombineAttributeParser<S> for DebuggerViualizerParser {
|
||||
cx: &mut AcceptContext<'_, '_, S>,
|
||||
args: &ArgParser,
|
||||
) -> impl IntoIterator<Item = Self::Item> {
|
||||
let single = cx.expect_single_element_list(args, cx.attr_span)?;
|
||||
let Some(l) = args.list() else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_list(attr_span, args);
|
||||
return None;
|
||||
};
|
||||
let Some(single) = l.single() else {
|
||||
cx.adcx().expected_single_argument(l.span);
|
||||
return None;
|
||||
};
|
||||
let Some(mi) = single.meta_item() else {
|
||||
cx.adcx().expected_name_value(single.span(), None);
|
||||
return None;
|
||||
|
||||
@@ -34,6 +34,7 @@ fn get<S: Stage>(
|
||||
pub(crate) struct DeprecatedParser;
|
||||
impl<S: Stage> SingleAttributeParser<S> for DeprecatedParser {
|
||||
const PATH: &[Symbol] = &[sym::deprecated];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Mod),
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
use rustc_hir::Target;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_session::lint::builtin::{
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES, MISPLACED_DIAGNOSTIC_ATTRIBUTES,
|
||||
};
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES;
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
use crate::attributes::{OnDuplicate, SingleAttributeParser};
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::errors::IncorrectDoNotRecommendLocation;
|
||||
use crate::parser::ArgParser;
|
||||
use crate::target_checking::{ALL_TARGETS, AllowedTargets};
|
||||
|
||||
@@ -17,32 +13,18 @@ pub(crate) struct DoNotRecommendParser;
|
||||
impl<S: Stage> SingleAttributeParser<S> for DoNotRecommendParser {
|
||||
const PATH: &[Symbol] = &[sym::diagnostic, sym::do_not_recommend];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
// "Allowed" on any target, noop on all but trait impls
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); // Checked in check_attr.
|
||||
const TEMPLATE: AttributeTemplate = template!(Word /*doesn't matter */);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let attr_span = cx.attr_span;
|
||||
if !matches!(args, ArgParser::NoArgs) {
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
|dcx, level| crate::errors::DoNotRecommendDoesNotExpectArgs.into_diag(dcx, level),
|
||||
AttributeLintKind::DoNotRecommendDoesNotExpectArgs,
|
||||
attr_span,
|
||||
);
|
||||
}
|
||||
|
||||
if !matches!(cx.target, Target::Impl { of_trait: true }) {
|
||||
let target_span = cx.target_span;
|
||||
cx.emit_dyn_lint(
|
||||
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
|
||||
move |dcx, level| {
|
||||
IncorrectDoNotRecommendLocation { target_span }.into_diag(dcx, level)
|
||||
},
|
||||
attr_span,
|
||||
);
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(AttributeKind::DoNotRecommend { attr_span })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
use std::ops::Range;
|
||||
|
||||
use rustc_errors::{Diagnostic, E0232};
|
||||
use rustc_errors::E0232;
|
||||
use rustc_hir::AttrPath;
|
||||
use rustc_hir::attrs::diagnostic::{
|
||||
Directive, FilterFormatString, Flag, FormatArg, FormatString, LitOrArg, Name, NameValue,
|
||||
OnUnimplementedCondition, Piece, Predicate,
|
||||
};
|
||||
use rustc_hir::lints::{AttributeLintKind, FormatWarning};
|
||||
use rustc_macros::Diagnostic;
|
||||
use rustc_parse_format::{
|
||||
Argument, FormatSpec, ParseError, ParseMode, Parser, Piece as RpfPiece, Position,
|
||||
@@ -17,10 +18,6 @@ use rustc_span::{Ident, InnerSpan, Span, Symbol, kw, sym};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::errors::{
|
||||
FormatWarning, IgnoredDiagnosticOption, MalFormedDiagnosticAttributeLint,
|
||||
MissingOptionsForDiagnosticAttribute, NonMetaItemDiagnosticAttribute, WrappedParserError,
|
||||
};
|
||||
use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, MetaItemParser};
|
||||
|
||||
pub(crate) mod do_not_recommend;
|
||||
@@ -28,7 +25,6 @@ pub(crate) mod on_const;
|
||||
pub(crate) mod on_move;
|
||||
pub(crate) mod on_unimplemented;
|
||||
pub(crate) mod on_unknown;
|
||||
pub(crate) mod on_unmatch_args;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub(crate) enum Mode {
|
||||
@@ -42,73 +38,6 @@ pub(crate) enum Mode {
|
||||
DiagnosticOnMove,
|
||||
/// `#[diagnostic::on_unknown]`
|
||||
DiagnosticOnUnknown,
|
||||
/// `#[diagnostic::on_unmatch_args]`
|
||||
DiagnosticOnUnmatchArgs,
|
||||
}
|
||||
|
||||
impl Mode {
|
||||
fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::RustcOnUnimplemented => "rustc_on_unimplemented",
|
||||
Self::DiagnosticOnUnimplemented => "diagnostic::on_unimplemented",
|
||||
Self::DiagnosticOnConst => "diagnostic::on_const",
|
||||
Self::DiagnosticOnMove => "diagnostic::on_move",
|
||||
Self::DiagnosticOnUnknown => "diagnostic::on_unknown",
|
||||
Self::DiagnosticOnUnmatchArgs => "diagnostic::on_unmatch_args",
|
||||
}
|
||||
}
|
||||
|
||||
fn expected_options(&self) -> &'static str {
|
||||
const DEFAULT: &str =
|
||||
"at least one of the `message`, `note` and `label` options are expected";
|
||||
match self {
|
||||
Self::RustcOnUnimplemented => {
|
||||
"see <https://rustc-dev-guide.rust-lang.org/diagnostics.html#rustc_on_unimplemented>"
|
||||
}
|
||||
Self::DiagnosticOnUnimplemented => DEFAULT,
|
||||
Self::DiagnosticOnConst => DEFAULT,
|
||||
Self::DiagnosticOnMove => DEFAULT,
|
||||
Self::DiagnosticOnUnknown => DEFAULT,
|
||||
Self::DiagnosticOnUnmatchArgs => DEFAULT,
|
||||
}
|
||||
}
|
||||
|
||||
fn allowed_options(&self) -> &'static str {
|
||||
const DEFAULT: &str = "only `message`, `note` and `label` are allowed as options";
|
||||
match self {
|
||||
Self::RustcOnUnimplemented => {
|
||||
"see <https://rustc-dev-guide.rust-lang.org/diagnostics.html#rustc_on_unimplemented>"
|
||||
}
|
||||
Self::DiagnosticOnUnimplemented => DEFAULT,
|
||||
Self::DiagnosticOnConst => DEFAULT,
|
||||
Self::DiagnosticOnMove => DEFAULT,
|
||||
Self::DiagnosticOnUnknown => DEFAULT,
|
||||
Self::DiagnosticOnUnmatchArgs => DEFAULT,
|
||||
}
|
||||
}
|
||||
|
||||
fn allowed_format_arguments(&self) -> &'static str {
|
||||
match self {
|
||||
Self::RustcOnUnimplemented => {
|
||||
"see <https://rustc-dev-guide.rust-lang.org/diagnostics.html#rustc_on_unimplemented> for allowed format arguments"
|
||||
}
|
||||
Self::DiagnosticOnUnimplemented => {
|
||||
"only `Self` and generics of the trait are allowed as a format argument"
|
||||
}
|
||||
Self::DiagnosticOnConst => {
|
||||
"only `Self` and generics of the implementation are allowed as a format argument"
|
||||
}
|
||||
Self::DiagnosticOnMove => {
|
||||
"only `This`, `Self` and generics of the type are allowed as a format argument"
|
||||
}
|
||||
Self::DiagnosticOnUnknown => {
|
||||
"only `This` is allowed as a format argument, referring to the failed import"
|
||||
}
|
||||
Self::DiagnosticOnUnmatchArgs => {
|
||||
"only `This` is allowed as a format argument, referring to the macro's name"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn merge_directives<S: Stage>(
|
||||
@@ -138,12 +67,12 @@ fn merge<T, S: Stage>(
|
||||
match (first, later) {
|
||||
(Some(_) | None, None) => {}
|
||||
(Some((first_span, _)), Some((later_span, _))) => {
|
||||
let first_span = *first_span;
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
move |dcx, level| {
|
||||
IgnoredDiagnosticOption { first_span, later_span, option_name }
|
||||
.into_diag(dcx, level)
|
||||
AttributeLintKind::IgnoredDiagnosticOption {
|
||||
first_span: *first_span,
|
||||
later_span,
|
||||
option_name,
|
||||
},
|
||||
later_span,
|
||||
);
|
||||
@@ -154,55 +83,6 @@ fn merge<T, S: Stage>(
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_list<'p, S: Stage>(
|
||||
cx: &mut AcceptContext<'_, '_, S>,
|
||||
args: &'p ArgParser,
|
||||
mode: Mode,
|
||||
) -> Option<&'p MetaItemListParser> {
|
||||
let span = cx.attr_span;
|
||||
match args {
|
||||
ArgParser::List(items) if items.len() != 0 => return Some(items),
|
||||
ArgParser::List(list) => {
|
||||
// We're dealing with `#[diagnostic::attr()]`.
|
||||
// This can be because that is what the user typed, but that's also what we'd see
|
||||
// if the user used non-metaitem syntax. See `ArgParser::from_attr_args`.
|
||||
cx.emit_dyn_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
move |dcx, level| NonMetaItemDiagnosticAttribute.into_diag(dcx, level),
|
||||
list.span,
|
||||
);
|
||||
}
|
||||
ArgParser::NoArgs => {
|
||||
cx.emit_dyn_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
move |dcx, level| {
|
||||
MissingOptionsForDiagnosticAttribute {
|
||||
attribute: mode.as_str(),
|
||||
options: mode.expected_options(),
|
||||
}
|
||||
.into_diag(dcx, level)
|
||||
},
|
||||
span,
|
||||
);
|
||||
}
|
||||
ArgParser::NameValue(_) => {
|
||||
cx.emit_dyn_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
move |dcx, level| {
|
||||
MalFormedDiagnosticAttributeLint {
|
||||
attribute: mode.as_str(),
|
||||
options: mode.allowed_options(),
|
||||
span,
|
||||
}
|
||||
.into_diag(dcx, level)
|
||||
},
|
||||
span,
|
||||
);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn parse_directive_items<'p, S: Stage>(
|
||||
cx: &mut AcceptContext<'_, '_, S>,
|
||||
mode: Mode,
|
||||
@@ -220,43 +100,68 @@ fn parse_directive_items<'p, S: Stage>(
|
||||
let span = item.span();
|
||||
|
||||
macro malformed() {{
|
||||
cx.emit_dyn_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
move |dcx, level| {
|
||||
MalFormedDiagnosticAttributeLint {
|
||||
attribute: mode.as_str(),
|
||||
options: mode.allowed_options(),
|
||||
match mode {
|
||||
Mode::RustcOnUnimplemented => {
|
||||
cx.emit_err(NoValueInOnUnimplemented { span: item.span() });
|
||||
}
|
||||
Mode::DiagnosticOnUnimplemented => {
|
||||
cx.emit_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
AttributeLintKind::MalformedOnUnimplementedAttr { span },
|
||||
span,
|
||||
}
|
||||
.into_diag(dcx, level)
|
||||
},
|
||||
span,
|
||||
);
|
||||
);
|
||||
}
|
||||
Mode::DiagnosticOnConst => {
|
||||
cx.emit_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
AttributeLintKind::MalformedOnConstAttr { span },
|
||||
span,
|
||||
);
|
||||
}
|
||||
Mode::DiagnosticOnMove => {
|
||||
cx.emit_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
AttributeLintKind::MalformedOnMoveAttr { span },
|
||||
span,
|
||||
);
|
||||
}
|
||||
Mode::DiagnosticOnUnknown => {
|
||||
cx.emit_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
AttributeLintKind::MalformedOnUnknownAttr { span },
|
||||
span,
|
||||
);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}}
|
||||
|
||||
macro or_malformed($($code:tt)*) {{
|
||||
let Some(ret) = (
|
||||
try {
|
||||
$($code)*
|
||||
}
|
||||
) else {
|
||||
let Some(ret) = (||{
|
||||
Some($($code)*)
|
||||
})() else {
|
||||
malformed!()
|
||||
};
|
||||
ret
|
||||
}}
|
||||
|
||||
macro duplicate($name: ident, $($first_span:tt)*) {{
|
||||
let first_span = $($first_span)*;
|
||||
cx.emit_dyn_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
move |dcx, level| IgnoredDiagnosticOption {
|
||||
first_span,
|
||||
later_span: span,
|
||||
option_name: $name,
|
||||
}.into_diag(dcx, level),
|
||||
span,
|
||||
);
|
||||
match mode {
|
||||
Mode::RustcOnUnimplemented => {
|
||||
cx.emit_err(NoValueInOnUnimplemented { span: item.span() });
|
||||
}
|
||||
Mode::DiagnosticOnUnimplemented |Mode::DiagnosticOnConst | Mode::DiagnosticOnMove | Mode::DiagnosticOnUnknown => {
|
||||
cx.emit_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
AttributeLintKind::IgnoredDiagnosticOption {
|
||||
first_span: $($first_span)*,
|
||||
later_span: span,
|
||||
option_name: $name,
|
||||
},
|
||||
span,
|
||||
);
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
let item: &MetaItemParser = or_malformed!(item.meta_item()?);
|
||||
@@ -280,13 +185,12 @@ fn parse_directive_items<'p, S: Stage>(
|
||||
match parse_format_string(input.name, snippet, input.span, mode) {
|
||||
Ok((f, warnings)) => {
|
||||
for warning in warnings {
|
||||
let (FormatWarning::InvalidSpecifier { span }
|
||||
| FormatWarning::PositionalArgument { span }
|
||||
| FormatWarning::IndexedArgument { span }
|
||||
| FormatWarning::DisallowedPlaceholder { span, .. }) = warning;
|
||||
cx.emit_dyn_lint(
|
||||
let (FormatWarning::InvalidSpecifier { span, .. }
|
||||
| FormatWarning::PositionalArgument { span, .. }
|
||||
| FormatWarning::DisallowedPlaceholder { span }) = warning;
|
||||
cx.emit_lint(
|
||||
MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
|
||||
move |dcx, level| warning.into_diag(dcx, level),
|
||||
AttributeLintKind::MalformedDiagnosticFormat { warning },
|
||||
span,
|
||||
);
|
||||
}
|
||||
@@ -294,15 +198,12 @@ fn parse_directive_items<'p, S: Stage>(
|
||||
f
|
||||
}
|
||||
Err(e) => {
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
|
||||
move |dcx, level| {
|
||||
WrappedParserError {
|
||||
description: &e.description,
|
||||
label: &e.label,
|
||||
span: slice_span(input.span, e.span.clone(), is_snippet),
|
||||
}
|
||||
.into_diag(dcx, level)
|
||||
AttributeLintKind::DiagnosticWrappedParserError {
|
||||
description: e.description,
|
||||
label: e.label,
|
||||
span: slice_span(input.span, e.span, is_snippet),
|
||||
},
|
||||
input.span,
|
||||
);
|
||||
@@ -346,7 +247,7 @@ fn parse_directive_items<'p, S: Stage>(
|
||||
}
|
||||
(Mode::RustcOnUnimplemented, sym::on) => {
|
||||
if is_root {
|
||||
let items = or_malformed!(item.args().as_list()?);
|
||||
let items = or_malformed!(item.args().list()?);
|
||||
let mut iter = items.mixed();
|
||||
let condition: &MetaItemOrLitParser = match iter.next() {
|
||||
Some(c) => c,
|
||||
@@ -436,74 +337,36 @@ fn parse_arg(
|
||||
is_source_literal: bool,
|
||||
) -> FormatArg {
|
||||
let span = slice_span(input_span, arg.position_span.clone(), is_source_literal);
|
||||
if matches!(mode, Mode::DiagnosticOnUnknown) {
|
||||
warnings.push(FormatWarning::DisallowedPlaceholder { span });
|
||||
return FormatArg::AsIs(sym::empty_braces);
|
||||
}
|
||||
|
||||
match arg.position {
|
||||
// Something like "hello {name}"
|
||||
Position::ArgumentNamed(name) => match (mode, Symbol::intern(name)) {
|
||||
(Mode::RustcOnUnimplemented, sym::ItemContext) => FormatArg::ItemContext,
|
||||
|
||||
// Like `{This}`, but sugared.
|
||||
// FIXME(mejrs) maybe rename/rework this or something
|
||||
// if we want to apply this to other attrs?
|
||||
(Mode::RustcOnUnimplemented, sym::Trait) => FormatArg::Trait,
|
||||
|
||||
// Some diagnostic attributes can use `{This}` to refer to the annotated item.
|
||||
// For those that don't, we continue and maybe use it as a generic parameter.
|
||||
//
|
||||
// FIXME(mejrs) `DiagnosticOnUnimplemented` is intentionally not here;
|
||||
// that requires lang approval which is best kept for a standalone PR.
|
||||
(
|
||||
Mode::RustcOnUnimplemented
|
||||
| Mode::DiagnosticOnUnknown
|
||||
| Mode::DiagnosticOnMove
|
||||
| Mode::DiagnosticOnUnmatchArgs,
|
||||
sym::This,
|
||||
) => FormatArg::This,
|
||||
|
||||
// `{Self}`; the self type.
|
||||
// - For trait declaration attributes that's the type that does not implement it.
|
||||
// - for trait impl attributes, the implemented for type.
|
||||
// - For ADT attributes, that's the type (which will be identical to `{This}`)
|
||||
// - For everything else it doesn't make sense.
|
||||
(
|
||||
Mode::RustcOnUnimplemented
|
||||
| Mode::DiagnosticOnUnimplemented
|
||||
| Mode::DiagnosticOnMove
|
||||
| Mode::DiagnosticOnConst,
|
||||
kw::SelfUpper,
|
||||
) => FormatArg::SelfUpper,
|
||||
|
||||
// Generic parameters.
|
||||
// FIXME(mejrs) unfortunately, all the "special" symbols above might fall through,
|
||||
// but at this time we are not aware of what generic parameters the trait actually has.
|
||||
// If we find `ItemContext` or something we have to assume that's a generic parameter.
|
||||
// We lint against that in `check_attr.rs` though.
|
||||
(
|
||||
Mode::RustcOnUnimplemented
|
||||
| Mode::DiagnosticOnUnimplemented
|
||||
| Mode::DiagnosticOnMove
|
||||
| Mode::DiagnosticOnConst,
|
||||
generic_param,
|
||||
) => FormatArg::GenericParam { generic_param, span },
|
||||
|
||||
// Generics are explicitly not allowed, we print those back as is.
|
||||
(Mode::DiagnosticOnUnknown | Mode::DiagnosticOnUnmatchArgs, as_is) => {
|
||||
warnings.push(FormatWarning::DisallowedPlaceholder {
|
||||
span,
|
||||
attr: mode.as_str(),
|
||||
allowed: mode.allowed_format_arguments(),
|
||||
});
|
||||
return FormatArg::AsIs(Symbol::intern(&format!("{{{as_is}}}")));
|
||||
}
|
||||
// Only `#[rustc_on_unimplemented]` can use these
|
||||
(Mode::RustcOnUnimplemented { .. }, sym::ItemContext) => FormatArg::ItemContext,
|
||||
(Mode::RustcOnUnimplemented { .. }, sym::This) => FormatArg::This,
|
||||
(Mode::RustcOnUnimplemented { .. }, sym::Trait) => FormatArg::Trait,
|
||||
// Any attribute can use these
|
||||
(_, kw::SelfUpper) => FormatArg::SelfUpper,
|
||||
(_, generic_param) => FormatArg::GenericParam { generic_param, span },
|
||||
},
|
||||
|
||||
// `{:1}` and `{}` are ignored
|
||||
Position::ArgumentIs(idx) => {
|
||||
warnings.push(FormatWarning::IndexedArgument { span });
|
||||
warnings.push(FormatWarning::PositionalArgument {
|
||||
span,
|
||||
help: format!("use `{{{idx}}}` to print a number in braces"),
|
||||
});
|
||||
FormatArg::AsIs(Symbol::intern(&format!("{{{idx}}}")))
|
||||
}
|
||||
Position::ArgumentImplicitlyIs(_) => {
|
||||
warnings.push(FormatWarning::PositionalArgument { span });
|
||||
warnings.push(FormatWarning::PositionalArgument {
|
||||
span,
|
||||
help: String::from("use `{{}}` to print empty braces"),
|
||||
});
|
||||
FormatArg::AsIs(sym::empty_braces)
|
||||
}
|
||||
}
|
||||
@@ -523,7 +386,7 @@ fn warn_on_format_spec(
|
||||
.as_ref()
|
||||
.map(|inner| slice_span(input_span, inner.clone(), is_source_literal))
|
||||
.unwrap_or(input_span);
|
||||
warnings.push(FormatWarning::InvalidSpecifier { span })
|
||||
warnings.push(FormatWarning::InvalidSpecifier { span, name: spec.ty.into() })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -556,7 +419,7 @@ fn parse_predicate(input: &MetaItemOrLitParser) -> Result<Predicate, InvalidOnCl
|
||||
sym::any => Ok(Predicate::Any(parse_predicate_sequence(mis)?)),
|
||||
sym::all => Ok(Predicate::All(parse_predicate_sequence(mis)?)),
|
||||
sym::not => {
|
||||
if let Some(single) = mis.as_single() {
|
||||
if let Some(single) = mis.single() {
|
||||
Ok(Predicate::Not(Box::new(parse_predicate(single)?)))
|
||||
} else {
|
||||
Err(InvalidOnClause::ExpectedOnePredInNot { span: mis.span })
|
||||
@@ -677,6 +540,15 @@ pub(crate) enum InvalidOnClause {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("this attribute must have a value", code = E0232)]
|
||||
#[note("e.g. `#[rustc_on_unimplemented(message=\"foo\")]`")]
|
||||
pub(crate) struct NoValueInOnUnimplemented {
|
||||
#[primary_span]
|
||||
#[label("expected value here")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(
|
||||
"using multiple `rustc_on_unimplemented` (or mixing it with `diagnostic::on_unimplemented`) is not supported"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_hir::attrs::diagnostic::Directive;
|
||||
use rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES;
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES;
|
||||
|
||||
use crate::attributes::diagnostic::*;
|
||||
use crate::attributes::prelude::*;
|
||||
use crate::errors::DiagnosticOnConstOnlyForTraitImpls;
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct OnConstParser {
|
||||
span: Option<Span>,
|
||||
@@ -17,40 +17,42 @@ impl<S: Stage> AttributeParser<S> for OnConstParser {
|
||||
template!(List: &[r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#]),
|
||||
|this, cx, args| {
|
||||
if !cx.features().diagnostic_on_const() {
|
||||
// `UnknownDiagnosticAttribute` is emitted in rustc_resolve/macros.rs
|
||||
return;
|
||||
}
|
||||
|
||||
let span = cx.attr_span;
|
||||
this.span = Some(span);
|
||||
|
||||
// FIXME(mejrs) no constness field on `Target`,
|
||||
// so non-constness is still checked in check_attr.rs
|
||||
if !matches!(cx.target, Target::Impl { of_trait: true }) {
|
||||
let target_span = cx.target_span;
|
||||
cx.emit_dyn_lint(
|
||||
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
|
||||
move |dcx, level| {
|
||||
DiagnosticOnConstOnlyForTraitImpls { target_span }.into_diag(dcx, level)
|
||||
},
|
||||
span,
|
||||
);
|
||||
return;
|
||||
}
|
||||
let items = match args {
|
||||
ArgParser::List(items) if items.len() != 0 => items,
|
||||
ArgParser::NoArgs | ArgParser::List(_) => {
|
||||
cx.emit_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
AttributeLintKind::MissingOptionsForOnConst,
|
||||
span,
|
||||
);
|
||||
return;
|
||||
}
|
||||
ArgParser::NameValue(_) => {
|
||||
cx.emit_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
AttributeLintKind::MalformedOnConstAttr { span },
|
||||
span,
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let mode = Mode::DiagnosticOnConst;
|
||||
|
||||
let Some(items) = parse_list(cx, args, mode) else { return };
|
||||
|
||||
let Some(directive) = parse_directive_items(cx, mode, items.mixed(), true) else {
|
||||
let Some(directive) =
|
||||
parse_directive_items(cx, Mode::DiagnosticOnConst, items.mixed(), true)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
merge_directives(cx, &mut this.directive, (span, directive));
|
||||
},
|
||||
)];
|
||||
|
||||
// "Allowed" on all targets; noop on anything but non-const trait impls;
|
||||
// this linted on in parser.
|
||||
//FIXME Still checked in `check_attr.rs`
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
|
||||
|
||||
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_feature::template;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES;
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES;
|
||||
use rustc_span::sym;
|
||||
|
||||
use crate::attributes::diagnostic::*;
|
||||
use crate::attributes::prelude::*;
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::errors::DiagnosticOnMoveOnlyForAdt;
|
||||
use crate::parser::ArgParser;
|
||||
use crate::target_checking::{ALL_TARGETS, AllowedTargets};
|
||||
|
||||
@@ -25,25 +24,30 @@ impl OnMoveParser {
|
||||
mode: Mode,
|
||||
) {
|
||||
if !cx.features().diagnostic_on_move() {
|
||||
// `UnknownDiagnosticAttribute` is emitted in rustc_resolve/macros.rs
|
||||
return;
|
||||
}
|
||||
|
||||
let span = cx.attr_span;
|
||||
self.span = Some(span);
|
||||
|
||||
if !matches!(cx.target, Target::Enum | Target::Struct | Target::Union) {
|
||||
cx.emit_dyn_lint(
|
||||
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
|
||||
move |dcx, level| DiagnosticOnMoveOnlyForAdt.into_diag(dcx, level),
|
||||
let Some(list) = args.list() else {
|
||||
cx.emit_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
AttributeLintKind::MissingOptionsForOnMove,
|
||||
span,
|
||||
);
|
||||
return;
|
||||
};
|
||||
|
||||
if list.is_empty() {
|
||||
cx.emit_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
AttributeLintKind::OnMoveMalformedAttrExpectedLiteralOrDelimiter,
|
||||
list.span,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(items) = parse_list(cx, args, mode) else { return };
|
||||
|
||||
if let Some(directive) = parse_directive_items(cx, mode, items.mixed(), true) {
|
||||
if let Some(directive) = parse_directive_items(cx, mode, list.mixed(), true) {
|
||||
merge_directives(cx, &mut self.directive, (span, directive));
|
||||
}
|
||||
}
|
||||
@@ -56,8 +60,6 @@ impl<S: Stage> AttributeParser<S> for OnMoveParser {
|
||||
this.parse(cx, args, Mode::DiagnosticOnMove);
|
||||
},
|
||||
)];
|
||||
|
||||
// "Allowed" for all targets but noop if used on not-adt.
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
|
||||
|
||||
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_hir::attrs::diagnostic::Directive;
|
||||
use rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES;
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES;
|
||||
|
||||
use crate::attributes::diagnostic::*;
|
||||
use crate::attributes::prelude::*;
|
||||
use crate::errors::DiagnosticOnUnimplementedOnlyForTraits;
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct OnUnimplementedParser {
|
||||
@@ -22,16 +21,33 @@ impl OnUnimplementedParser {
|
||||
let span = cx.attr_span;
|
||||
self.span = Some(span);
|
||||
|
||||
// If target is not a trait, returning early will make `finalize` emit a
|
||||
// `AttributeKind::OnUnimplemented {span, directive: None }`, to prevent it being
|
||||
// accidentally used on non-trait items like trait aliases.
|
||||
if !matches!(cx.target, Target::Trait) {
|
||||
cx.emit_dyn_lint(
|
||||
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
|
||||
move |dcx, level| DiagnosticOnUnimplementedOnlyForTraits.into_diag(dcx, level),
|
||||
span,
|
||||
);
|
||||
// Lint later emitted in check_attr
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(items) = parse_list(cx, args, mode) else { return };
|
||||
let items = match args {
|
||||
ArgParser::List(items) if items.len() != 0 => items,
|
||||
ArgParser::NoArgs | ArgParser::List(_) => {
|
||||
cx.emit_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
AttributeLintKind::MissingOptionsForOnUnimplemented,
|
||||
span,
|
||||
);
|
||||
return;
|
||||
}
|
||||
ArgParser::NameValue(_) => {
|
||||
cx.emit_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
AttributeLintKind::MalformedOnUnimplementedAttr { span },
|
||||
span,
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(directive) = parse_directive_items(cx, mode, items.mixed(), true) {
|
||||
merge_directives(cx, &mut self.directive, (span, directive));
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_hir::attrs::diagnostic::Directive;
|
||||
use rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES;
|
||||
use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES;
|
||||
|
||||
use crate::ShouldEmit;
|
||||
use crate::attributes::diagnostic::*;
|
||||
use crate::attributes::prelude::*;
|
||||
use crate::errors::DiagnosticOnUnknownOnlyForImports;
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct OnUnknownParser {
|
||||
@@ -20,32 +17,31 @@ impl OnUnknownParser {
|
||||
args: &ArgParser,
|
||||
mode: Mode,
|
||||
) {
|
||||
if let Some(features) = cx.features
|
||||
&& !features.diagnostic_on_unknown()
|
||||
{
|
||||
// `UnknownDiagnosticAttribute` is emitted in rustc_resolve/macros.rs
|
||||
if !cx.features().diagnostic_on_unknown() {
|
||||
return;
|
||||
}
|
||||
let span = cx.attr_span;
|
||||
self.span = Some(span);
|
||||
|
||||
// At early parsing we get passed `Target::Crate` regardless of the item we're on.
|
||||
// Only do target checking if we're late.
|
||||
let early = matches!(cx.stage.should_emit(), ShouldEmit::Nothing);
|
||||
|
||||
if !early && !matches!(cx.target, Target::Use) {
|
||||
let target_span = cx.target_span;
|
||||
cx.emit_dyn_lint(
|
||||
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
|
||||
move |dcx, level| {
|
||||
DiagnosticOnUnknownOnlyForImports { target_span }.into_diag(dcx, level)
|
||||
},
|
||||
span,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(items) = parse_list(cx, args, mode) else { return };
|
||||
let items = match args {
|
||||
ArgParser::List(items) if !items.is_empty() => items,
|
||||
ArgParser::NoArgs | ArgParser::List(_) => {
|
||||
cx.emit_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
AttributeLintKind::MissingOptionsForOnUnknown,
|
||||
span,
|
||||
);
|
||||
return;
|
||||
}
|
||||
ArgParser::NameValue(_) => {
|
||||
cx.emit_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
AttributeLintKind::MalformedOnUnknownAttr { span },
|
||||
span,
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(directive) = parse_directive_items(cx, mode, items.mixed(), true) {
|
||||
merge_directives(cx, &mut self.directive, (span, directive));
|
||||
@@ -61,7 +57,7 @@ impl<S: Stage> AttributeParser<S> for OnUnknownParser {
|
||||
this.parse(cx, args, Mode::DiagnosticOnUnknown);
|
||||
},
|
||||
)];
|
||||
// "Allowed" for all targets, but noop for all but use statements.
|
||||
//FIXME attribute is not parsed for non-use statements but diagnostics are issued in `check_attr.rs`
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
|
||||
|
||||
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_hir::attrs::diagnostic::Directive;
|
||||
use rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES;
|
||||
|
||||
use crate::attributes::diagnostic::*;
|
||||
use crate::attributes::prelude::*;
|
||||
use crate::errors::DiagnosticOnUnmatchArgsOnlyForMacros;
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct OnUnmatchArgsParser {
|
||||
span: Option<Span>,
|
||||
directive: Option<(Span, Directive)>,
|
||||
}
|
||||
|
||||
impl<S: Stage> AttributeParser<S> for OnUnmatchArgsParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
|
||||
&[sym::diagnostic, sym::on_unmatch_args],
|
||||
template!(List: &[r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#]),
|
||||
|this, cx, args| {
|
||||
if !cx.features().diagnostic_on_unmatch_args() {
|
||||
return;
|
||||
}
|
||||
|
||||
let span = cx.attr_span;
|
||||
this.span = Some(span);
|
||||
|
||||
if !matches!(cx.target, Target::MacroDef) {
|
||||
cx.emit_dyn_lint(
|
||||
MISPLACED_DIAGNOSTIC_ATTRIBUTES,
|
||||
move |dcx, level| DiagnosticOnUnmatchArgsOnlyForMacros.into_diag(dcx, level),
|
||||
span,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let mode = Mode::DiagnosticOnUnmatchArgs;
|
||||
let Some(items) = parse_list(cx, args, mode) else { return };
|
||||
|
||||
let Some(directive) = parse_directive_items(cx, mode, items.mixed(), true) else {
|
||||
return;
|
||||
};
|
||||
merge_directives(cx, &mut this.directive, (span, directive));
|
||||
},
|
||||
)];
|
||||
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
|
||||
|
||||
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
if let Some(span) = self.span {
|
||||
Some(AttributeKind::OnUnmatchArgs {
|
||||
span,
|
||||
directive: self.directive.map(|d| Box::new(d.1)),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
use rustc_ast::ast::{AttrStyle, LitKind, MetaItemLit};
|
||||
use rustc_errors::{Applicability, Diagnostic, msg};
|
||||
use rustc_errors::msg;
|
||||
use rustc_feature::template;
|
||||
use rustc_hir::Target;
|
||||
use rustc_hir::attrs::{
|
||||
AttributeKind, CfgEntry, CfgHideShow, CfgInfo, DocAttribute, DocInline, HideOrShow,
|
||||
};
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::{Span, Symbol, edition, sym};
|
||||
use thin_vec::ThinVec;
|
||||
@@ -12,13 +13,6 @@ use thin_vec::ThinVec;
|
||||
use super::prelude::{ALL_TARGETS, AllowedTargets};
|
||||
use super::{AcceptMapping, AttributeParser};
|
||||
use crate::context::{AcceptContext, FinalizeContext, Stage};
|
||||
use crate::errors::{
|
||||
AttrCrateLevelOnly, DocAliasDuplicated, DocAutoCfgExpectsHideOrShow,
|
||||
DocAutoCfgHideShowExpectsList, DocAutoCfgHideShowUnexpectedItem, DocAutoCfgWrongLiteral,
|
||||
DocTestLiteral, DocTestTakesList, DocTestUnknown, DocUnknownAny, DocUnknownInclude,
|
||||
DocUnknownPasses, DocUnknownPlugins, DocUnknownSpotlight, ExpectedNameValue, ExpectedNoArgs,
|
||||
IllFormedAttributeInput, MalformedDoc,
|
||||
};
|
||||
use crate::parser::{ArgParser, MetaItemOrLitParser, MetaItemParser, OwnedPathParser};
|
||||
use crate::session_diagnostics::{
|
||||
DocAliasBadChar, DocAliasEmpty, DocAliasMalformed, DocAliasStartEnd, DocAttrNotCrateLevel,
|
||||
@@ -68,9 +62,9 @@ fn check_attr_not_crate_level<S: Stage>(
|
||||
/// Checks that an attribute is used at the crate level. Returns `true` if valid.
|
||||
fn check_attr_crate_level<S: Stage>(cx: &mut AcceptContext<'_, '_, S>, span: Span) -> bool {
|
||||
if cx.shared.target != Target::Crate {
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
|dcx, level| AttrCrateLevelOnly.into_diag(dcx, level),
|
||||
AttributeLintKind::AttrCrateLevelOnly,
|
||||
span,
|
||||
);
|
||||
return false;
|
||||
@@ -84,18 +78,18 @@ fn expected_name_value<S: Stage>(
|
||||
span: Span,
|
||||
_name: Option<Symbol>,
|
||||
) {
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
|dcx, level| ExpectedNameValue.into_diag(dcx, level),
|
||||
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_dyn_lint(
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
|dcx, level| ExpectedNoArgs.into_diag(dcx, level),
|
||||
AttributeLintKind::ExpectedNoArgs,
|
||||
span,
|
||||
);
|
||||
}
|
||||
@@ -107,9 +101,9 @@ fn expected_string_literal<S: Stage>(
|
||||
span: Span,
|
||||
_actual_literal: Option<&MetaItemLit>,
|
||||
) {
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
|dcx, level| MalformedDoc.into_diag(dcx, level),
|
||||
AttributeLintKind::MalformedDoc,
|
||||
span,
|
||||
);
|
||||
}
|
||||
@@ -177,15 +171,12 @@ impl DocParser {
|
||||
|
||||
if let Some(used_span) = self.attribute.no_crate_inject {
|
||||
let unused_span = path.span();
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
move |dcx, level| {
|
||||
rustc_errors::lints::UnusedDuplicate {
|
||||
this: unused_span,
|
||||
other: used_span,
|
||||
warning: true,
|
||||
}
|
||||
.into_diag(dcx, level)
|
||||
AttributeLintKind::UnusedDuplicate {
|
||||
this: unused_span,
|
||||
other: used_span,
|
||||
warning: true,
|
||||
},
|
||||
unused_span,
|
||||
);
|
||||
@@ -199,13 +190,13 @@ impl DocParser {
|
||||
self.attribute.no_crate_inject = Some(path.span())
|
||||
}
|
||||
Some(sym::attr) => {
|
||||
let Some(list) = args.as_list() else {
|
||||
let Some(list) = args.list() else {
|
||||
// FIXME: remove this method once merged and uncomment the line below instead.
|
||||
// cx.expected_list(cx.attr_span, args);
|
||||
let span = cx.attr_span;
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
|dcx, level| MalformedDoc.into_diag(dcx, level),
|
||||
AttributeLintKind::MalformedDoc,
|
||||
span,
|
||||
);
|
||||
return;
|
||||
@@ -217,16 +208,16 @@ impl DocParser {
|
||||
}
|
||||
}
|
||||
Some(name) => {
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
move |dcx, level| DocTestUnknown { name }.into_diag(dcx, level),
|
||||
AttributeLintKind::DocTestUnknown { name },
|
||||
path.span(),
|
||||
);
|
||||
}
|
||||
None => {
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
|dcx, level| DocTestLiteral.into_diag(dcx, level),
|
||||
AttributeLintKind::DocTestLiteral,
|
||||
path.span(),
|
||||
);
|
||||
}
|
||||
@@ -261,9 +252,9 @@ impl DocParser {
|
||||
}
|
||||
|
||||
if let Some(first_definition) = self.attribute.aliases.get(&alias).copied() {
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
|
||||
move |dcx, level| DocAliasDuplicated { first_definition }.into_diag(dcx, level),
|
||||
AttributeLintKind::DuplicateDocAlias { first_definition },
|
||||
span,
|
||||
);
|
||||
}
|
||||
@@ -349,9 +340,9 @@ impl DocParser {
|
||||
ArgParser::List(list) => {
|
||||
for meta in list.mixed() {
|
||||
let MetaItemOrLitParser::MetaItemParser(item) = meta else {
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
|dcx, level| DocAutoCfgExpectsHideOrShow.into_diag(dcx, level),
|
||||
AttributeLintKind::DocAutoCfgExpectsHideOrShow,
|
||||
meta.span(),
|
||||
);
|
||||
continue;
|
||||
@@ -360,20 +351,18 @@ impl DocParser {
|
||||
Some(sym::hide) => (HideOrShow::Hide, sym::hide),
|
||||
Some(sym::show) => (HideOrShow::Show, sym::show),
|
||||
_ => {
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
|dcx, level| DocAutoCfgExpectsHideOrShow.into_diag(dcx, level),
|
||||
AttributeLintKind::DocAutoCfgExpectsHideOrShow,
|
||||
item.span(),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let ArgParser::List(list) = item.args() else {
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
move |dcx, level| {
|
||||
DocAutoCfgHideShowExpectsList { attr_name }.into_diag(dcx, level)
|
||||
},
|
||||
AttributeLintKind::DocAutoCfgHideShowExpectsList { attr_name },
|
||||
item.span(),
|
||||
);
|
||||
continue;
|
||||
@@ -383,12 +372,9 @@ impl DocParser {
|
||||
|
||||
for item in list.mixed() {
|
||||
let MetaItemOrLitParser::MetaItemParser(sub_item) = item else {
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
move |dcx, level| {
|
||||
DocAutoCfgHideShowUnexpectedItem { attr_name }
|
||||
.into_diag(dcx, level)
|
||||
},
|
||||
AttributeLintKind::DocAutoCfgHideShowUnexpectedItem { attr_name },
|
||||
item.span(),
|
||||
);
|
||||
continue;
|
||||
@@ -399,9 +385,9 @@ impl DocParser {
|
||||
// FIXME: remove this method once merged and uncomment the line
|
||||
// below instead.
|
||||
// cx.expected_identifier(sub_item.path().span());
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
|dcx, level| MalformedDoc.into_diag(dcx, level),
|
||||
AttributeLintKind::MalformedDoc,
|
||||
sub_item.path().span(),
|
||||
);
|
||||
continue;
|
||||
@@ -426,11 +412,10 @@ impl DocParser {
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
move |dcx, level| {
|
||||
DocAutoCfgHideShowUnexpectedItem { attr_name }
|
||||
.into_diag(dcx, level)
|
||||
AttributeLintKind::DocAutoCfgHideShowUnexpectedItem {
|
||||
attr_name,
|
||||
},
|
||||
sub_item.span(),
|
||||
);
|
||||
@@ -444,9 +429,9 @@ impl DocParser {
|
||||
ArgParser::NameValue(nv) => {
|
||||
let MetaItemLit { kind: LitKind::Bool(bool_value), span, .. } = nv.value_as_lit()
|
||||
else {
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
move |dcx, level| DocAutoCfgWrongLiteral.into_diag(dcx, level),
|
||||
AttributeLintKind::DocAutoCfgWrongLiteral,
|
||||
nv.value_span,
|
||||
);
|
||||
return;
|
||||
@@ -587,10 +572,10 @@ impl DocParser {
|
||||
}),
|
||||
Some(sym::auto_cfg) => self.parse_auto_cfg(cx, path, args),
|
||||
Some(sym::test) => {
|
||||
let Some(list) = args.as_list() else {
|
||||
cx.emit_dyn_lint(
|
||||
let Some(list) = args.list() else {
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
|dcx, level| DocTestTakesList.into_diag(dcx, level),
|
||||
AttributeLintKind::DocTestTakesList,
|
||||
args.span().unwrap_or(path.span()),
|
||||
);
|
||||
return;
|
||||
@@ -605,9 +590,9 @@ impl DocParser {
|
||||
// FIXME: remove this method once merged and uncomment the line
|
||||
// below instead.
|
||||
// cx.unexpected_literal(lit.span);
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
|dcx, level| MalformedDoc.into_diag(dcx, level),
|
||||
AttributeLintKind::MalformedDoc,
|
||||
lit.span,
|
||||
);
|
||||
}
|
||||
@@ -615,11 +600,10 @@ impl DocParser {
|
||||
}
|
||||
}
|
||||
Some(sym::spotlight) => {
|
||||
let span = path.span();
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
move |dcx, level| DocUnknownSpotlight { sugg_span: span }.into_diag(dcx, level),
|
||||
span,
|
||||
AttributeLintKind::DocUnknownSpotlight { span: path.span() },
|
||||
path.span(),
|
||||
);
|
||||
}
|
||||
Some(sym::include) if let Some(nv) = args.name_value() => {
|
||||
@@ -627,53 +611,43 @@ impl DocParser {
|
||||
AttrStyle::Outer => "",
|
||||
AttrStyle::Inner => "!",
|
||||
};
|
||||
let value = nv.value_as_lit().symbol;
|
||||
let span = path.span();
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
move |dcx, level| {
|
||||
DocUnknownInclude {
|
||||
inner,
|
||||
value,
|
||||
sugg: (span, Applicability::MaybeIncorrect),
|
||||
}
|
||||
.into_diag(dcx, level)
|
||||
AttributeLintKind::DocUnknownInclude {
|
||||
inner,
|
||||
value: nv.value_as_lit().symbol,
|
||||
span: path.span(),
|
||||
},
|
||||
span,
|
||||
path.span(),
|
||||
);
|
||||
}
|
||||
Some(name @ (sym::passes | sym::no_default_passes)) => {
|
||||
let span = path.span();
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
move |dcx, level| {
|
||||
DocUnknownPasses { name, note_span: span }.into_diag(dcx, level)
|
||||
},
|
||||
span,
|
||||
AttributeLintKind::DocUnknownPasses { name, span: path.span() },
|
||||
path.span(),
|
||||
);
|
||||
}
|
||||
Some(sym::plugins) => {
|
||||
let span = path.span();
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
move |dcx, level| DocUnknownPlugins { label_span: span }.into_diag(dcx, level),
|
||||
span,
|
||||
AttributeLintKind::DocUnknownPlugins { span: path.span() },
|
||||
path.span(),
|
||||
);
|
||||
}
|
||||
Some(name) => {
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
move |dcx, level| DocUnknownAny { name }.into_diag(dcx, level),
|
||||
AttributeLintKind::DocUnknownAny { name },
|
||||
path.span(),
|
||||
);
|
||||
}
|
||||
None => {
|
||||
let full_name =
|
||||
path.segments().map(|s| s.as_str()).intersperse("::").collect::<String>();
|
||||
let name = Symbol::intern(&full_name);
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
move |dcx, level| DocUnknownAny { name }.into_diag(dcx, level),
|
||||
AttributeLintKind::DocUnknownAny { name: Symbol::intern(&full_name) },
|
||||
path.span(),
|
||||
);
|
||||
}
|
||||
@@ -689,10 +663,12 @@ impl DocParser {
|
||||
ArgParser::NoArgs => {
|
||||
let suggestions = cx.adcx().suggestions();
|
||||
let span = cx.attr_span;
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
|
||||
move |dcx, level| {
|
||||
IllFormedAttributeInput::new(&suggestions, None, None).into_diag(dcx, level)
|
||||
AttributeLintKind::IllFormedAttributeInput {
|
||||
suggestions,
|
||||
docs: None,
|
||||
help: None,
|
||||
},
|
||||
span,
|
||||
);
|
||||
|
||||
@@ -37,7 +37,10 @@ impl<S: Stage> SingleAttributeParser<S> for InlineParser {
|
||||
match args {
|
||||
ArgParser::NoArgs => Some(AttributeKind::Inline(InlineAttr::Hint, cx.attr_span)),
|
||||
ArgParser::List(list) => {
|
||||
let l = cx.expect_single(list)?;
|
||||
let Some(l) = list.single() else {
|
||||
cx.adcx().expected_single_argument(list.span);
|
||||
return None;
|
||||
};
|
||||
|
||||
match l.meta_item().and_then(|i| i.path().word_sym()) {
|
||||
Some(sym::always) => {
|
||||
@@ -64,6 +67,7 @@ pub(crate) struct RustcForceInlineParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_force_inline];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
@@ -75,7 +79,10 @@ impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
|
||||
let reason = match args {
|
||||
ArgParser::NoArgs => None,
|
||||
ArgParser::List(list) => {
|
||||
let l = cx.expect_single(list)?;
|
||||
let Some(l) = list.single() else {
|
||||
cx.adcx().expected_single_argument(list.span);
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(reason) = l.lit().and_then(|i| i.kind.str()) else {
|
||||
cx.adcx().expected_string_literal(l.span(), l.lit());
|
||||
|
||||
@@ -15,11 +15,16 @@ impl<S: Stage> SingleAttributeParser<S> for InstructionSetParser {
|
||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||
]);
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["set"], "https://doc.rust-lang.org/reference/attributes/codegen.html#the-instruction_set-attribute");
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
const POSSIBLE_SYMBOLS: &[Symbol] = &[sym::arm_a32, sym::arm_t32];
|
||||
const POSSIBLE_ARM_SYMBOLS: &[Symbol] = &[sym::a32, sym::t32];
|
||||
let maybe_meta_item = cx.expect_single_element_list(args, cx.attr_span)?;
|
||||
let Some(maybe_meta_item) = args.list().and_then(MetaItemListParser::single) else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_specific_argument(attr_span, POSSIBLE_SYMBOLS);
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(meta_item) = maybe_meta_item.meta_item() else {
|
||||
cx.adcx().expected_specific_argument(maybe_meta_item.span(), POSSIBLE_SYMBOLS);
|
||||
|
||||
@@ -5,20 +5,17 @@ use rustc_hir::attrs::*;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::edition::Edition::Edition2024;
|
||||
use rustc_span::kw;
|
||||
use rustc_target::spec::{Arch, BinaryFormat};
|
||||
|
||||
use super::prelude::*;
|
||||
use super::util::parse_single_integer;
|
||||
use crate::attributes::AttributeSafety;
|
||||
use crate::attributes::cfg::parse_cfg_entry;
|
||||
use crate::session_diagnostics::{
|
||||
AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ExportSymbolsNeedsStatic,
|
||||
ImportNameTypeRaw, ImportNameTypeX86, IncompatibleWasmLink, InvalidLinkModifier,
|
||||
InvalidMachoSection, InvalidMachoSectionReason, LinkFrameworkApple, LinkOrdinalOutOfRange,
|
||||
LinkRequiresName, MultipleModifiers, NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows,
|
||||
WholeArchiveNeedsStatic,
|
||||
LinkFrameworkApple, LinkOrdinalOutOfRange, LinkRequiresName, MultipleModifiers,
|
||||
NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows, WholeArchiveNeedsStatic,
|
||||
};
|
||||
|
||||
pub(crate) struct LinkNameParser;
|
||||
@@ -391,7 +388,12 @@ impl LinkParser {
|
||||
cx.adcx().duplicate_key(item.span(), sym::cfg);
|
||||
return true;
|
||||
}
|
||||
let Some(link_cfg) = cx.expect_single_element_list(item.args(), item.span()) else {
|
||||
let Some(link_cfg) = item.args().list() else {
|
||||
cx.adcx().expected_list(item.span(), item.args());
|
||||
return true;
|
||||
};
|
||||
let Some(link_cfg) = link_cfg.single() else {
|
||||
cx.adcx().expected_single_argument(item.span());
|
||||
return true;
|
||||
};
|
||||
if !features.link_cfg() {
|
||||
@@ -463,33 +465,9 @@ impl LinkParser {
|
||||
|
||||
pub(crate) struct LinkSectionParser;
|
||||
|
||||
fn check_link_section_macho(name: Symbol) -> Result<(), InvalidMachoSectionReason> {
|
||||
let mut parts = name.as_str().split(',').map(|s| s.trim());
|
||||
|
||||
// The segment can be empty.
|
||||
let _segment = parts.next();
|
||||
|
||||
// But the section is required.
|
||||
let section = match parts.next() {
|
||||
None | Some("") => return Err(InvalidMachoSectionReason::MissingSection),
|
||||
Some(section) => section,
|
||||
};
|
||||
|
||||
if section.len() > 16 {
|
||||
return Err(InvalidMachoSectionReason::SectionTooLong { section: section.to_string() });
|
||||
}
|
||||
|
||||
// LLVM also checks the other components of the section specifier, but that logic is hard to
|
||||
// keep in sync. We skip it here for now, assuming that if you got that far you'll be able
|
||||
// to interpret the LLVM errors.
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
|
||||
const PATH: &[Symbol] = &[sym::link_section];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
|
||||
Allow(Target::Static),
|
||||
Allow(Target::Fn),
|
||||
@@ -519,18 +497,6 @@ impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
|
||||
return None;
|
||||
}
|
||||
|
||||
// We (currently) only validate macho section specifiers.
|
||||
match cx.sess.target.binary_format {
|
||||
BinaryFormat::MachO => match check_link_section_macho(name) {
|
||||
Ok(()) => {}
|
||||
Err(reason) => {
|
||||
cx.emit_err(InvalidMachoSection { name_span: nv.value_span, reason });
|
||||
return None;
|
||||
}
|
||||
},
|
||||
BinaryFormat::Coff | BinaryFormat::Elf | BinaryFormat::Wasm | BinaryFormat::Xcoff => {}
|
||||
}
|
||||
|
||||
Some(LinkSection { name, span: cx.attr_span })
|
||||
}
|
||||
}
|
||||
@@ -538,6 +504,7 @@ impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
|
||||
pub(crate) struct ExportStableParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for ExportStableParser {
|
||||
const PATH: &[Symbol] = &[sym::export_stable];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs`
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ExportStable;
|
||||
}
|
||||
@@ -545,7 +512,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for ExportStableParser {
|
||||
pub(crate) struct FfiConstParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for FfiConstParser {
|
||||
const PATH: &[Symbol] = &[sym::ffi_const];
|
||||
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiConst;
|
||||
}
|
||||
@@ -553,7 +520,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for FfiConstParser {
|
||||
pub(crate) struct FfiPureParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for FfiPureParser {
|
||||
const PATH: &[Symbol] = &[sym::ffi_pure];
|
||||
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiPure;
|
||||
}
|
||||
@@ -561,6 +528,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for FfiPureParser {
|
||||
pub(crate) struct RustcStdInternalSymbolParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcStdInternalSymbolParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_std_internal_symbol];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::ForeignFn),
|
||||
@@ -574,6 +542,7 @@ pub(crate) struct LinkOrdinalParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for LinkOrdinalParser {
|
||||
const PATH: &[Symbol] = &[sym::link_ordinal];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::ForeignFn),
|
||||
Allow(Target::ForeignStatic),
|
||||
@@ -614,6 +583,7 @@ pub(crate) struct LinkageParser;
|
||||
impl<S: Stage> SingleAttributeParser<S> for LinkageParser {
|
||||
const PATH: &[Symbol] = &[sym::linkage];
|
||||
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
@@ -696,6 +666,7 @@ pub(crate) struct NeedsAllocatorParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for NeedsAllocatorParser {
|
||||
const PATH: &[Symbol] = &[sym::needs_allocator];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsAllocator;
|
||||
}
|
||||
@@ -704,6 +675,7 @@ pub(crate) struct CompilerBuiltinsParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for CompilerBuiltinsParser {
|
||||
const PATH: &[Symbol] = &[sym::compiler_builtins];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CompilerBuiltins;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ use super::prelude::*;
|
||||
pub(crate) struct RustcAsPtrParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcAsPtrParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_as_ptr];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
@@ -16,6 +17,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcAsPtrParser {
|
||||
pub(crate) struct RustcPubTransparentParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcPubTransparentParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_pub_transparent];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Struct),
|
||||
Allow(Target::Enum),
|
||||
@@ -27,6 +29,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcPubTransparentParser {
|
||||
pub(crate) struct RustcPassByValueParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcPassByValueParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_pass_by_value];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Struct),
|
||||
Allow(Target::Enum),
|
||||
@@ -38,6 +41,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcPassByValueParser {
|
||||
pub(crate) struct RustcShouldNotBeCalledOnConstItemsParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcShouldNotBeCalledOnConstItemsParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_should_not_be_called_on_const_items];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
||||
|
||||
@@ -3,6 +3,7 @@ use super::prelude::*;
|
||||
pub(crate) struct LoopMatchParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for LoopMatchParser {
|
||||
const PATH: &[Symbol] = &[sym::loop_match];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Expression)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::LoopMatch;
|
||||
}
|
||||
@@ -10,6 +11,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for LoopMatchParser {
|
||||
pub(crate) struct ConstContinueParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for ConstContinueParser {
|
||||
const PATH: &[Symbol] = &[sym::const_continue];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Expression)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::ConstContinue;
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ impl<S: Stage> SingleAttributeParser<S> for MacroExportParser {
|
||||
let local_inner_macros = match args {
|
||||
ArgParser::NoArgs => false,
|
||||
ArgParser::List(list) => {
|
||||
let Some(l) = list.as_single() else {
|
||||
let Some(l) = list.single() else {
|
||||
cx.adcx().warn_ill_formed_attribute_input(INVALID_MACRO_EXPORT_ARGUMENTS);
|
||||
return None;
|
||||
};
|
||||
@@ -167,6 +167,7 @@ pub(crate) struct CollapseDebugInfoParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for CollapseDebugInfoParser {
|
||||
const PATH: &[Symbol] = &[sym::collapse_debuginfo];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const TEMPLATE: AttributeTemplate = template!(
|
||||
List: &["no", "external", "yes"],
|
||||
"https://doc.rust-lang.org/reference/attributes/debugger.html#the-collapse_debuginfo-attribute"
|
||||
@@ -174,7 +175,15 @@ impl<S: Stage> SingleAttributeParser<S> for CollapseDebugInfoParser {
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let single = cx.expect_single_element_list(args, cx.attr_span)?;
|
||||
let Some(list) = args.list() else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_list(attr_span, args);
|
||||
return None;
|
||||
};
|
||||
let Some(single) = list.single() else {
|
||||
cx.adcx().expected_single_argument(list.span);
|
||||
return None;
|
||||
};
|
||||
let Some(mi) = single.meta_item() else {
|
||||
cx.adcx().expected_not_literal(single.span());
|
||||
return None;
|
||||
@@ -202,6 +211,7 @@ 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;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ use std::marker::PhantomData;
|
||||
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
@@ -98,7 +97,6 @@ pub(crate) trait AttributeParser<S: Stage>: Default + 'static {
|
||||
/// If an attribute has this symbol, the `accept` function will be called on it.
|
||||
const ATTRIBUTES: AcceptMapping<Self, S>;
|
||||
const ALLOWED_TARGETS: AllowedTargets;
|
||||
const SAFETY: AttributeSafety = AttributeSafety::Normal;
|
||||
|
||||
/// The parser has gotten a chance to accept the attributes on an item,
|
||||
/// here it can produce an attribute.
|
||||
@@ -128,8 +126,7 @@ pub(crate) trait SingleAttributeParser<S: Stage>: 'static {
|
||||
|
||||
/// Configures what to do when when the same attribute is
|
||||
/// applied more than once on the same syntax node.
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const SAFETY: AttributeSafety = AttributeSafety::Normal;
|
||||
const ON_DUPLICATE: OnDuplicate<S>;
|
||||
|
||||
const ALLOWED_TARGETS: AllowedTargets;
|
||||
|
||||
@@ -161,14 +158,13 @@ impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S>
|
||||
if let Some(pa) = T::convert(cx, args) {
|
||||
if let Some((_, used)) = group.1 {
|
||||
T::ON_DUPLICATE.exec::<T>(cx, used, cx.attr_span);
|
||||
} else {
|
||||
group.1 = Some((pa, cx.attr_span));
|
||||
}
|
||||
|
||||
group.1 = Some((pa, cx.attr_span));
|
||||
}
|
||||
},
|
||||
)];
|
||||
const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
|
||||
const SAFETY: AttributeSafety = T::SAFETY;
|
||||
|
||||
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
Some(self.1?.0)
|
||||
@@ -221,18 +217,6 @@ impl<S: Stage> OnDuplicate<S> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub enum AttributeSafety {
|
||||
/// Normal attribute that does not need `#[unsafe(...)]`
|
||||
Normal,
|
||||
/// Unsafe attribute that requires safety obligations to be discharged.
|
||||
///
|
||||
/// An error is emitted when `#[unsafe(...)]` is omitted, except when the attribute's edition
|
||||
/// is less than the one stored in `unsafe_since`. This handles attributes that were safe in
|
||||
/// earlier editions, but become unsafe in later ones.
|
||||
Unsafe { unsafe_since: Option<Edition> },
|
||||
}
|
||||
|
||||
/// An even simpler version of [`SingleAttributeParser`]:
|
||||
/// now automatically check that there are no arguments provided to the attribute.
|
||||
///
|
||||
@@ -240,9 +224,8 @@ pub enum AttributeSafety {
|
||||
//
|
||||
pub(crate) trait NoArgsAttributeParser<S: Stage>: 'static {
|
||||
const PATH: &[Symbol];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ON_DUPLICATE: OnDuplicate<S>;
|
||||
const ALLOWED_TARGETS: AllowedTargets;
|
||||
const SAFETY: AttributeSafety = AttributeSafety::Normal;
|
||||
|
||||
/// Create the [`AttributeKind`] given attribute's [`Span`].
|
||||
const CREATE: fn(Span) -> AttributeKind;
|
||||
@@ -259,7 +242,6 @@ impl<T: NoArgsAttributeParser<S>, S: Stage> Default for WithoutArgs<T, S> {
|
||||
impl<T: NoArgsAttributeParser<S>, S: Stage> SingleAttributeParser<S> for WithoutArgs<T, S> {
|
||||
const PATH: &[Symbol] = T::PATH;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = T::ON_DUPLICATE;
|
||||
const SAFETY: AttributeSafety = T::SAFETY;
|
||||
const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word);
|
||||
|
||||
@@ -289,7 +271,6 @@ pub(crate) trait CombineAttributeParser<S: Stage>: 'static {
|
||||
/// For example, individual representations from `#[repr(...)]` attributes into an `AttributeKind::Repr(x)`,
|
||||
/// where `x` is a vec of these individual reprs.
|
||||
const CONVERT: ConvertFn<Self::Item>;
|
||||
const SAFETY: AttributeSafety = AttributeSafety::Normal;
|
||||
|
||||
const ALLOWED_TARGETS: AllowedTargets;
|
||||
|
||||
@@ -331,7 +312,6 @@ impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S
|
||||
group.items.extend(T::extend(cx, args))
|
||||
})];
|
||||
const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
|
||||
const SAFETY: AttributeSafety = T::SAFETY;
|
||||
|
||||
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
if let Some(first_span) = self.first_span {
|
||||
|
||||
@@ -4,6 +4,7 @@ pub(crate) struct MustNotSuspendParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for MustNotSuspendParser {
|
||||
const PATH: &[rustc_span::Symbol] = &[sym::must_not_suspend];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Struct),
|
||||
Allow(Target::Enum),
|
||||
|
||||
@@ -2,7 +2,7 @@ use rustc_hir::Target;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
use crate::attributes::NoArgsAttributeParser;
|
||||
use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
|
||||
use crate::context::Stage;
|
||||
use crate::target_checking::AllowedTargets;
|
||||
use crate::target_checking::Policy::Allow;
|
||||
@@ -11,6 +11,7 @@ pub(crate) struct PinV2Parser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for PinV2Parser {
|
||||
const PATH: &[Symbol] = &[sym::pin_v2];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Enum),
|
||||
Allow(Target::Struct),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_session::lint::builtin::AMBIGUOUS_DERIVE_HELPERS;
|
||||
|
||||
use super::prelude::*;
|
||||
@@ -9,6 +9,7 @@ const PROC_MACRO_ALLOWED_TARGETS: AllowedTargets =
|
||||
pub(crate) struct ProcMacroParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for ProcMacroParser {
|
||||
const PATH: &[Symbol] = &[sym::proc_macro];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = PROC_MACRO_ALLOWED_TARGETS;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::ProcMacro;
|
||||
}
|
||||
@@ -16,6 +17,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for ProcMacroParser {
|
||||
pub(crate) struct ProcMacroAttributeParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for ProcMacroAttributeParser {
|
||||
const PATH: &[Symbol] = &[sym::proc_macro_attribute];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = PROC_MACRO_ALLOWED_TARGETS;
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::ProcMacroAttribute;
|
||||
}
|
||||
@@ -23,6 +25,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for ProcMacroAttributeParser {
|
||||
pub(crate) struct ProcMacroDeriveParser;
|
||||
impl<S: Stage> SingleAttributeParser<S> for ProcMacroDeriveParser {
|
||||
const PATH: &[Symbol] = &[sym::proc_macro_derive];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = PROC_MACRO_ALLOWED_TARGETS;
|
||||
const TEMPLATE: AttributeTemplate = template!(
|
||||
List: &["TraitName", "TraitName, attributes(name1, name2, ...)"],
|
||||
@@ -42,6 +45,7 @@ impl<S: Stage> SingleAttributeParser<S> for ProcMacroDeriveParser {
|
||||
pub(crate) struct RustcBuiltinMacroParser;
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcBuiltinMacroParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_builtin_macro];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]);
|
||||
const TEMPLATE: AttributeTemplate =
|
||||
template!(List: &["TraitName", "TraitName, attributes(name1, name2, ...)"]);
|
||||
@@ -57,7 +61,7 @@ fn parse_derive_like<S: Stage>(
|
||||
args: &ArgParser,
|
||||
trait_name_mandatory: bool,
|
||||
) -> Option<(Option<Symbol>, ThinVec<Symbol>)> {
|
||||
let Some(list) = args.as_list() else {
|
||||
let Some(list) = args.list() else {
|
||||
// For #[rustc_builtin_macro], it is permitted to leave out the trait name
|
||||
if args.no_args().is_ok() && !trait_name_mandatory {
|
||||
return Some((None, ThinVec::new()));
|
||||
@@ -101,7 +105,10 @@ fn parse_derive_like<S: Stage>(
|
||||
cx.adcx().expected_specific_argument(attrs.span(), &[sym::attributes]);
|
||||
return None;
|
||||
}
|
||||
let attr_list = cx.expect_list(attr_list.args(), attrs.span())?;
|
||||
let Some(attr_list) = attr_list.args().list() else {
|
||||
cx.adcx().expected_list(attrs.span(), attr_list.args());
|
||||
return None;
|
||||
};
|
||||
|
||||
// Parse item in `attributes(...)` argument
|
||||
for attr in attr_list.mixed() {
|
||||
@@ -122,9 +129,9 @@ fn parse_derive_like<S: Stage>(
|
||||
return None;
|
||||
}
|
||||
if rustc_feature::is_builtin_attr_name(ident.name) {
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
AMBIGUOUS_DERIVE_HELPERS,
|
||||
|dcx, level| crate::errors::AmbiguousDeriveHelpers.into_diag(dcx, level),
|
||||
AttributeLintKind::AmbiguousDeriveHelpers,
|
||||
ident.span,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ use rustc_hir::Target;
|
||||
use rustc_hir::attrs::{AttributeKind, MirDialect, MirPhase};
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
use super::OnDuplicate;
|
||||
use crate::attributes::SingleAttributeParser;
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::parser::ArgParser;
|
||||
@@ -17,12 +18,18 @@ pub(crate) struct CustomMirParser;
|
||||
impl<S: Stage> SingleAttributeParser<S> for CustomMirParser {
|
||||
const PATH: &[rustc_span::Symbol] = &[sym::custom_mir];
|
||||
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
||||
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &[r#"dialect = "...", phase = "...""#]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let list = cx.expect_list(args, cx.attr_span)?;
|
||||
let Some(list) = args.list() else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_list(attr_span, args);
|
||||
return None;
|
||||
};
|
||||
|
||||
let mut dialect = None;
|
||||
let mut phase = None;
|
||||
@@ -75,7 +82,7 @@ fn extract_value<S: Stage>(
|
||||
}
|
||||
|
||||
let Some(val) = arg.name_value() else {
|
||||
cx.adcx().expected_name_value(span, Some(key));
|
||||
cx.adcx().expected_single_argument(arg.span().unwrap_or(span));
|
||||
*failed = true;
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -32,7 +32,9 @@ impl<S: Stage> CombineAttributeParser<S> for ReprParser {
|
||||
) -> impl IntoIterator<Item = Self::Item> {
|
||||
let mut reprs = Vec::new();
|
||||
|
||||
let Some(list) = cx.expect_list(args, cx.attr_span) else {
|
||||
let Some(list) = args.list() else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_list(attr_span, args);
|
||||
return reprs;
|
||||
};
|
||||
|
||||
@@ -195,7 +197,7 @@ fn parse_repr_align<S: Stage>(
|
||||
) -> Option<ReprAttr> {
|
||||
use AlignKind::*;
|
||||
|
||||
let Some(align) = list.as_single() else {
|
||||
let Some(align) = list.single() else {
|
||||
match align_kind {
|
||||
Packed => {
|
||||
cx.emit_err(session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg {
|
||||
@@ -294,7 +296,8 @@ impl RustcAlignParser {
|
||||
cx.adcx().expected_list(attr_span, args);
|
||||
}
|
||||
ArgParser::List(list) => {
|
||||
let Some(align) = cx.expect_single(list) else {
|
||||
let Some(align) = list.single() else {
|
||||
cx.adcx().expected_single_argument(list.span);
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ pub(crate) struct RustcAllocatorParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcAllocatorParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_allocator];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets =
|
||||
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcAllocator;
|
||||
@@ -13,6 +14,7 @@ pub(crate) struct RustcAllocatorZeroedParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcAllocatorZeroedParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_allocator_zeroed];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets =
|
||||
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcAllocatorZeroed;
|
||||
@@ -22,6 +24,7 @@ pub(crate) struct RustcAllocatorZeroedVariantParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcAllocatorZeroedVariantParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_allocator_zeroed_variant];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets =
|
||||
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "function");
|
||||
@@ -40,6 +43,7 @@ pub(crate) struct RustcDeallocatorParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDeallocatorParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_deallocator];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets =
|
||||
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDeallocator;
|
||||
@@ -49,6 +53,7 @@ pub(crate) struct RustcReallocatorParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcReallocatorParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_reallocator];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets =
|
||||
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcReallocator;
|
||||
|
||||
@@ -10,6 +10,7 @@ pub(crate) struct RustcDumpUserArgsParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpUserArgsParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_dump_user_args];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpUserArgs;
|
||||
}
|
||||
@@ -18,6 +19,7 @@ pub(crate) struct RustcDumpDefParentsParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpDefParentsParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_dump_def_parents];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpDefParents;
|
||||
}
|
||||
@@ -35,6 +37,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcDumpDefPathParser {
|
||||
Allow(Target::ForeignStatic),
|
||||
Allow(Target::Impl { of_trait: false }),
|
||||
]);
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word);
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
if let Err(span) = args.no_args() {
|
||||
@@ -49,6 +52,7 @@ pub(crate) struct RustcDumpHiddenTypeOfOpaquesParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpHiddenTypeOfOpaquesParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_dump_hidden_type_of_opaques];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpHiddenTypeOfOpaques;
|
||||
}
|
||||
@@ -57,6 +61,7 @@ pub(crate) struct RustcDumpInferredOutlivesParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpInferredOutlivesParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_dump_inferred_outlives];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Struct),
|
||||
Allow(Target::Enum),
|
||||
@@ -70,6 +75,7 @@ pub(crate) struct RustcDumpItemBoundsParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpItemBoundsParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_dump_item_bounds];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::AssocTy)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpItemBounds;
|
||||
}
|
||||
@@ -96,7 +102,9 @@ impl<S: Stage> CombineAttributeParser<S> for RustcDumpLayoutParser {
|
||||
cx: &mut AcceptContext<'_, '_, S>,
|
||||
args: &ArgParser,
|
||||
) -> impl IntoIterator<Item = Self::Item> {
|
||||
let Some(items) = cx.expect_list(args, cx.attr_span) else {
|
||||
let ArgParser::List(items) = args else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_list(attr_span, args);
|
||||
return vec![];
|
||||
};
|
||||
|
||||
@@ -140,6 +148,7 @@ pub(crate) struct RustcDumpObjectLifetimeDefaultsParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpObjectLifetimeDefaultsParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_dump_object_lifetime_defaults];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::AssocConst),
|
||||
Allow(Target::AssocTy),
|
||||
@@ -166,6 +175,7 @@ pub(crate) struct RustcDumpPredicatesParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpPredicatesParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_dump_predicates];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::AssocConst),
|
||||
Allow(Target::AssocTy),
|
||||
@@ -202,6 +212,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcDumpSymbolNameParser {
|
||||
Allow(Target::ForeignStatic),
|
||||
Allow(Target::Impl { of_trait: false }),
|
||||
]);
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word);
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
if let Err(span) = args.no_args() {
|
||||
@@ -216,6 +227,7 @@ pub(crate) struct RustcDumpVariancesParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpVariancesParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_dump_variances];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Enum),
|
||||
Allow(Target::Fn),
|
||||
@@ -233,6 +245,7 @@ pub(crate) struct RustcDumpVariancesOfOpaquesParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpVariancesOfOpaquesParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_dump_variances_of_opaques];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpVariancesOfOpaques;
|
||||
}
|
||||
@@ -241,6 +254,7 @@ pub(crate) struct RustcDumpVtableParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpVtableParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_dump_vtable];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Impl { of_trait: true }),
|
||||
Allow(Target::TyAlias),
|
||||
|
||||
@@ -6,11 +6,11 @@ use rustc_hir::attrs::{
|
||||
BorrowckGraphvizFormatKind, CguFields, CguKind, DivergingBlockBehavior,
|
||||
DivergingFallbackBehavior, RustcCleanAttribute, RustcCleanQueries, RustcMirKind,
|
||||
};
|
||||
use rustc_session::errors;
|
||||
use rustc_span::Symbol;
|
||||
|
||||
use super::prelude::*;
|
||||
use super::util::parse_single_integer;
|
||||
use crate::errors;
|
||||
use crate::session_diagnostics::{
|
||||
AttributeRequiresOpt, CguFieldsMissing, RustcScalableVectorCountOutOfRange, UnknownLangItem,
|
||||
};
|
||||
@@ -19,6 +19,7 @@ pub(crate) struct RustcMainParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcMainParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_main];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcMain;
|
||||
}
|
||||
@@ -27,10 +28,15 @@ pub(crate) struct RustcMustImplementOneOfParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcMustImplementOneOfParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_must_implement_one_of];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["function1, function2, ..."]);
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let list = cx.expect_list(args, cx.attr_span)?;
|
||||
let Some(list) = args.list() else {
|
||||
let span = cx.attr_span;
|
||||
cx.adcx().expected_list(span, args);
|
||||
return None;
|
||||
};
|
||||
|
||||
let mut fn_names = ThinVec::new();
|
||||
|
||||
@@ -68,6 +74,7 @@ pub(crate) struct RustcNeverReturnsNullPtrParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcNeverReturnsNullPtrParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_never_returns_null_ptr];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
@@ -81,6 +88,7 @@ pub(crate) struct RustcNoImplicitAutorefsParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcNoImplicitAutorefsParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_no_implicit_autorefs];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
@@ -96,6 +104,7 @@ pub(crate) struct RustcLayoutScalarValidRangeStartParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeStartParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_layout_scalar_valid_range_start];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["start"]);
|
||||
|
||||
@@ -109,6 +118,7 @@ pub(crate) struct RustcLayoutScalarValidRangeEndParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeEndParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_layout_scalar_valid_range_end];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["end"]);
|
||||
|
||||
@@ -122,11 +132,16 @@ pub(crate) struct RustcLegacyConstGenericsParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcLegacyConstGenericsParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_legacy_const_generics];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["N"]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let meta_items = cx.expect_list(args, cx.attr_span)?;
|
||||
let ArgParser::List(meta_items) = args else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_list(attr_span, args);
|
||||
return None;
|
||||
};
|
||||
|
||||
let mut parsed_indexes = ThinVec::new();
|
||||
let mut errored = false;
|
||||
@@ -161,6 +176,7 @@ pub(crate) struct RustcInheritOverflowChecksParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcInheritOverflowChecksParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_inherit_overflow_checks];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
@@ -174,10 +190,15 @@ pub(crate) struct RustcLintOptDenyFieldAccessParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcLintOptDenyFieldAccessParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_lint_opt_deny_field_access];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Field)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(Word);
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let arg = cx.expect_single_element_list(args, cx.attr_span)?;
|
||||
let Some(arg) = args.list().and_then(MetaItemListParser::single) else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_single_argument(attr_span);
|
||||
return None;
|
||||
};
|
||||
|
||||
let MetaItemOrLitParser::Lit(MetaItemLit { kind: LitKind::Str(lint_message, _), .. }) = arg
|
||||
else {
|
||||
@@ -193,6 +214,7 @@ pub(crate) struct RustcLintOptTyParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcLintOptTyParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_lint_opt_ty];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintOptTy;
|
||||
}
|
||||
@@ -202,7 +224,11 @@ fn parse_cgu_fields<S: Stage>(
|
||||
args: &ArgParser,
|
||||
accepts_kind: bool,
|
||||
) -> Option<(Symbol, Symbol, Option<CguKind>)> {
|
||||
let args = cx.expect_list(args, cx.attr_span)?;
|
||||
let Some(args) = args.list() else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_list(attr_span, args);
|
||||
return None;
|
||||
};
|
||||
|
||||
let mut cfg = None::<(Symbol, Span)>;
|
||||
let mut module = None::<(Symbol, Span)>;
|
||||
@@ -337,6 +363,7 @@ pub(crate) struct RustcDeprecatedSafe2024Parser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcDeprecatedSafe2024Parser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_deprecated_safe_2024];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
@@ -347,10 +374,19 @@ impl<S: Stage> SingleAttributeParser<S> for RustcDeprecatedSafe2024Parser {
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &[r#"audit_that = "...""#]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let single = cx.expect_single_element_list(args, cx.attr_span)?;
|
||||
let Some(args) = args.list() else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_list(attr_span, args);
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(single) = args.single() else {
|
||||
cx.adcx().expected_single_argument(args.span);
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(arg) = single.meta_item() else {
|
||||
cx.adcx().expected_name_value(single.span(), None);
|
||||
cx.adcx().expected_name_value(args.span, None);
|
||||
return None;
|
||||
};
|
||||
|
||||
@@ -377,6 +413,7 @@ pub(crate) struct RustcConversionSuggestionParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcConversionSuggestionParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_conversion_suggestion];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
@@ -391,6 +428,7 @@ pub(crate) struct RustcCaptureAnalysisParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcCaptureAnalysisParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_capture_analysis];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Closure)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcCaptureAnalysis;
|
||||
}
|
||||
@@ -399,6 +437,7 @@ pub(crate) struct RustcNeverTypeOptionsParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcNeverTypeOptionsParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_never_type_options];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &[
|
||||
r#"fallback = "unit", "never", "no""#,
|
||||
@@ -406,7 +445,11 @@ impl<S: Stage> SingleAttributeParser<S> for RustcNeverTypeOptionsParser {
|
||||
]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let list = cx.expect_list(args, cx.attr_span)?;
|
||||
let Some(list) = args.list() else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_list(attr_span, args);
|
||||
return None;
|
||||
};
|
||||
|
||||
let mut fallback = None::<Ident>;
|
||||
let mut diverging_block_default = None::<Ident>;
|
||||
@@ -477,6 +520,7 @@ pub(crate) struct RustcTrivialFieldReadsParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcTrivialFieldReadsParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_trivial_field_reads];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcTrivialFieldReads;
|
||||
}
|
||||
@@ -485,6 +529,7 @@ pub(crate) struct RustcNoMirInlineParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcNoMirInlineParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_no_mir_inline];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
@@ -495,25 +540,11 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcNoMirInlineParser {
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoMirInline;
|
||||
}
|
||||
|
||||
pub(crate) struct RustcNoWritableParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcNoWritableParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_no_writable];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Closure),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||
]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoWritable;
|
||||
}
|
||||
|
||||
pub(crate) struct RustcLintQueryInstabilityParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcLintQueryInstabilityParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_lint_query_instability];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
@@ -528,6 +559,7 @@ pub(crate) struct RustcRegionsParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcRegionsParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_regions];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
@@ -543,6 +575,7 @@ pub(crate) struct RustcLintUntrackedQueryInformationParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcLintUntrackedQueryInformationParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_lint_untracked_query_information];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
@@ -558,6 +591,7 @@ pub(crate) struct RustcSimdMonomorphizeLaneLimitParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcSimdMonomorphizeLaneLimitParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_simd_monomorphize_lane_limit];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
|
||||
|
||||
@@ -575,6 +609,7 @@ pub(crate) struct RustcScalableVectorParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcScalableVectorParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_scalable_vector];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(Word, List: &["count"]);
|
||||
|
||||
@@ -599,6 +634,7 @@ pub(crate) struct LangParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for LangParser {
|
||||
const PATH: &[Symbol] = &[sym::lang];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); // Targets are checked per lang item in `rustc_passes`
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
|
||||
|
||||
@@ -624,6 +660,7 @@ pub(crate) struct RustcHasIncoherentInherentImplsParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcHasIncoherentInherentImplsParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_has_incoherent_inherent_impls];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Trait),
|
||||
Allow(Target::Struct),
|
||||
@@ -638,6 +675,7 @@ pub(crate) struct PanicHandlerParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for PanicHandlerParser {
|
||||
const PATH: &[Symbol] = &[sym::panic_handler];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); // Targets are checked per lang item in `rustc_passes`
|
||||
const CREATE: fn(Span) -> AttributeKind = |span| AttributeKind::Lang(LangItem::PanicImpl, span);
|
||||
}
|
||||
@@ -646,6 +684,7 @@ pub(crate) struct RustcNounwindParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcNounwindParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_nounwind];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::ForeignFn),
|
||||
@@ -660,6 +699,7 @@ pub(crate) struct RustcOffloadKernelParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcOffloadKernelParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_offload_kernel];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcOffloadKernel;
|
||||
}
|
||||
@@ -687,7 +727,9 @@ impl<S: Stage> CombineAttributeParser<S> for RustcMirParser {
|
||||
cx: &mut AcceptContext<'_, '_, S>,
|
||||
args: &ArgParser,
|
||||
) -> impl IntoIterator<Item = Self::Item> {
|
||||
let Some(list) = cx.expect_list(args, cx.attr_span) else {
|
||||
let Some(list) = args.list() else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_list(attr_span, args);
|
||||
return ThinVec::new();
|
||||
};
|
||||
|
||||
@@ -756,6 +798,7 @@ pub(crate) struct RustcNonConstTraitMethodParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcNonConstTraitMethodParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_non_const_trait_method];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||
Allow(Target::Method(MethodKind::Trait { body: false })),
|
||||
@@ -807,8 +850,11 @@ impl<S: Stage> CombineAttributeParser<S> for RustcCleanParser {
|
||||
if !cx.cx.sess.opts.unstable_opts.query_dep_graph {
|
||||
cx.emit_err(AttributeRequiresOpt { span: cx.attr_span, opt: "-Z query-dep-graph" });
|
||||
}
|
||||
let list = cx.expect_list(args, cx.attr_span)?;
|
||||
|
||||
let Some(list) = args.list() else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_list(attr_span, args);
|
||||
return None;
|
||||
};
|
||||
let mut except = None;
|
||||
let mut loaded_from_disk = None;
|
||||
let mut cfg = None;
|
||||
@@ -871,6 +917,8 @@ pub(crate) struct RustcIfThisChangedParser;
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcIfThisChangedParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_if_this_changed];
|
||||
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
// tidy-alphabetical-start
|
||||
Allow(Target::AssocConst),
|
||||
@@ -905,7 +953,11 @@ impl<S: Stage> SingleAttributeParser<S> for RustcIfThisChangedParser {
|
||||
match args {
|
||||
ArgParser::NoArgs => Some(AttributeKind::RustcIfThisChanged(cx.attr_span, None)),
|
||||
ArgParser::List(list) => {
|
||||
let item = cx.expect_single(list)?;
|
||||
let Some(item) = list.single() else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_single_argument(attr_span);
|
||||
return None;
|
||||
};
|
||||
let Some(ident) = item.meta_item().and_then(|item| item.ident()) else {
|
||||
cx.adcx().expected_identifier(item.span());
|
||||
return None;
|
||||
@@ -963,7 +1015,11 @@ impl<S: Stage> CombineAttributeParser<S> for RustcThenThisWouldNeedParser {
|
||||
if !cx.cx.sess.opts.unstable_opts.query_dep_graph {
|
||||
cx.emit_err(AttributeRequiresOpt { span: cx.attr_span, opt: "-Z query-dep-graph" });
|
||||
}
|
||||
let item = cx.expect_single_element_list(args, cx.attr_span)?;
|
||||
let Some(item) = args.list().and_then(|l| l.single()) else {
|
||||
let inner_span = cx.inner_span;
|
||||
cx.adcx().expected_single_argument(inner_span);
|
||||
return None;
|
||||
};
|
||||
let Some(ident) = item.meta_item().and_then(|item| item.ident()) else {
|
||||
cx.adcx().expected_identifier(item.span());
|
||||
return None;
|
||||
@@ -976,6 +1032,7 @@ pub(crate) struct RustcInsignificantDtorParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcInsignificantDtorParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_insignificant_dtor];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Enum),
|
||||
Allow(Target::Struct),
|
||||
@@ -988,6 +1045,7 @@ pub(crate) struct RustcEffectiveVisibilityParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcEffectiveVisibilityParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_effective_visibility];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Use),
|
||||
Allow(Target::Static),
|
||||
@@ -1026,6 +1084,7 @@ pub(crate) struct RustcDiagnosticItemParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcDiagnosticItemParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_diagnostic_item];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Trait),
|
||||
Allow(Target::Struct),
|
||||
@@ -1064,6 +1123,7 @@ pub(crate) struct RustcDoNotConstCheckParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDoNotConstCheckParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_do_not_const_check];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
@@ -1078,6 +1138,7 @@ pub(crate) struct RustcNonnullOptimizationGuaranteedParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcNonnullOptimizationGuaranteedParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_nonnull_optimization_guaranteed];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNonnullOptimizationGuaranteed;
|
||||
}
|
||||
@@ -1086,6 +1147,7 @@ pub(crate) struct RustcStrictCoherenceParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcStrictCoherenceParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_strict_coherence];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Trait),
|
||||
Allow(Target::Struct),
|
||||
@@ -1100,6 +1162,7 @@ pub(crate) struct RustcReservationImplParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcReservationImplParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_reservation_impl];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets =
|
||||
AllowedTargets::AllowList(&[Allow(Target::Impl { of_trait: true })]);
|
||||
|
||||
@@ -1125,6 +1188,7 @@ pub(crate) struct PreludeImportParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for PreludeImportParser {
|
||||
const PATH: &[Symbol] = &[sym::prelude_import];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Use)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::PreludeImport;
|
||||
}
|
||||
@@ -1133,6 +1197,7 @@ pub(crate) struct RustcDocPrimitiveParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcDocPrimitiveParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_doc_primitive];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Mod)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "primitive name");
|
||||
|
||||
@@ -1156,6 +1221,7 @@ pub(crate) struct RustcIntrinsicParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcIntrinsicParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_intrinsic];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcIntrinsic;
|
||||
}
|
||||
@@ -1164,6 +1230,7 @@ pub(crate) struct RustcIntrinsicConstStableIndirectParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcIntrinsicConstStableIndirectParser {
|
||||
const PATH: &'static [Symbol] = &[sym::rustc_intrinsic_const_stable_indirect];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcIntrinsicConstStableIndirect;
|
||||
}
|
||||
@@ -1172,6 +1239,7 @@ pub(crate) struct RustcExhaustiveParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcExhaustiveParser {
|
||||
const PATH: &'static [Symbol] = &[sym::rustc_must_match_exhaustively];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Enum)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcMustMatchExhaustively;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ use super::prelude::*;
|
||||
pub(crate) struct MayDangleParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for MayDangleParser {
|
||||
const PATH: &[Symbol] = &[sym::may_dangle];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs`
|
||||
const CREATE: fn(span: Span) -> AttributeKind = AttributeKind::MayDangle;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ use std::num::NonZero;
|
||||
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_feature::ACCEPTED_LANG_FEATURES;
|
||||
use rustc_hir::attrs::UnstableRemovedFeature;
|
||||
use rustc_hir::target::GenericParamKind;
|
||||
use rustc_hir::{
|
||||
DefaultBodyStability, MethodKind, PartialConstStability, Stability, StabilityLevel,
|
||||
@@ -311,7 +310,11 @@ pub(crate) fn parse_stability<S: Stage>(
|
||||
let mut feature = None;
|
||||
let mut since = None;
|
||||
|
||||
let list = cx.expect_list(args, cx.attr_span)?;
|
||||
let ArgParser::List(list) = args else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_list(attr_span, args);
|
||||
return None;
|
||||
};
|
||||
|
||||
for param in list.mixed() {
|
||||
let param_span = param.span();
|
||||
@@ -379,7 +382,11 @@ pub(crate) fn parse_unstability<S: Stage>(
|
||||
let mut implied_by = None;
|
||||
let mut old_name = None;
|
||||
|
||||
let list = cx.expect_list(args, cx.attr_span)?;
|
||||
let ArgParser::List(list) = args else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_list(attr_span, args);
|
||||
return None;
|
||||
};
|
||||
|
||||
for param in list.mixed() {
|
||||
let Some(param) = param.meta_item() else {
|
||||
@@ -469,85 +476,3 @@ pub(crate) fn parse_unstability<S: Stage>(
|
||||
(Err(ErrorGuaranteed { .. }), _) | (_, Err(ErrorGuaranteed { .. })) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct UnstableRemovedParser;
|
||||
|
||||
impl<S: Stage> CombineAttributeParser<S> for UnstableRemovedParser {
|
||||
type Item = UnstableRemovedFeature;
|
||||
const PATH: &[Symbol] = &[sym::unstable_removed];
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const TEMPLATE: AttributeTemplate =
|
||||
template!(List: &[r#"feature = "name", reason = "...", link = "...", since = "version""#]);
|
||||
|
||||
const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::UnstableRemoved(items);
|
||||
|
||||
fn extend(
|
||||
cx: &mut AcceptContext<'_, '_, S>,
|
||||
args: &ArgParser,
|
||||
) -> impl IntoIterator<Item = Self::Item> {
|
||||
let mut feature = None;
|
||||
let mut reason = None;
|
||||
let mut link = None;
|
||||
let mut since = None;
|
||||
|
||||
if !cx.features().staged_api() {
|
||||
cx.emit_err(session_diagnostics::StabilityOutsideStd { span: cx.attr_span });
|
||||
return None;
|
||||
}
|
||||
|
||||
let list = cx.expect_list(args, cx.attr_span)?;
|
||||
|
||||
for param in list.mixed() {
|
||||
let Some(param) = param.meta_item() else {
|
||||
cx.adcx().expected_not_literal(param.span());
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(word) = param.path().word() else {
|
||||
cx.adcx().expected_specific_argument(
|
||||
param.span(),
|
||||
&[sym::feature, sym::reason, sym::link, sym::since],
|
||||
);
|
||||
return None;
|
||||
};
|
||||
match word.name {
|
||||
sym::feature => insert_value_into_option_or_error(cx, ¶m, &mut feature, word)?,
|
||||
sym::since => insert_value_into_option_or_error(cx, ¶m, &mut since, word)?,
|
||||
sym::reason => insert_value_into_option_or_error(cx, ¶m, &mut reason, word)?,
|
||||
sym::link => insert_value_into_option_or_error(cx, ¶m, &mut link, word)?,
|
||||
_ => {
|
||||
cx.adcx().expected_specific_argument(
|
||||
param.span(),
|
||||
&[sym::feature, sym::reason, sym::link, sym::since],
|
||||
);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check all the arguments are present
|
||||
let Some(feature) = feature else {
|
||||
cx.adcx().missing_name_value(list.span, sym::feature);
|
||||
return None;
|
||||
};
|
||||
let Some(reason) = reason else {
|
||||
cx.adcx().missing_name_value(list.span, sym::reason);
|
||||
return None;
|
||||
};
|
||||
let Some(link) = link else {
|
||||
cx.adcx().missing_name_value(list.span, sym::link);
|
||||
return None;
|
||||
};
|
||||
let Some(since) = since else {
|
||||
cx.adcx().missing_name_value(list.span, sym::since);
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(version) = parse_version(since) else {
|
||||
cx.emit_err(session_diagnostics::InvalidSince { span: cx.attr_span });
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(UnstableRemovedFeature { feature, reason, link, since: version })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,11 +28,10 @@ impl<S: Stage> SingleAttributeParser<S> for IgnoreParser {
|
||||
Some(str_value)
|
||||
}
|
||||
ArgParser::List(list) => {
|
||||
let help =
|
||||
list.as_single().and_then(|item| item.meta_item()).and_then(|item| {
|
||||
item.args().no_args().ok()?;
|
||||
Some(item.path().to_string())
|
||||
});
|
||||
let help = list.single().and_then(|item| item.meta_item()).and_then(|item| {
|
||||
item.args().no_args().ok()?;
|
||||
Some(item.path().to_string())
|
||||
});
|
||||
cx.adcx().warn_ill_formed_attribute_input_with_help(
|
||||
ILL_FORMED_ATTRIBUTE_INPUT,
|
||||
help,
|
||||
@@ -72,7 +71,10 @@ impl<S: Stage> SingleAttributeParser<S> for ShouldPanicParser {
|
||||
Some(str_value)
|
||||
}
|
||||
ArgParser::List(list) => {
|
||||
let single = cx.expect_single(list)?;
|
||||
let Some(single) = list.single() else {
|
||||
cx.adcx().expected_single_argument(list.span);
|
||||
return None;
|
||||
};
|
||||
let Some(single) = single.meta_item() else {
|
||||
cx.adcx().expected_name_value(single.span(), Some(sym::expected));
|
||||
return None;
|
||||
@@ -100,6 +102,7 @@ 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 ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
|
||||
|
||||
@@ -126,6 +129,7 @@ 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 ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::TyAlias),
|
||||
@@ -138,13 +142,17 @@ impl<S: Stage> SingleAttributeParser<S> for RustcAbiParser {
|
||||
]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let Some(args) = args.as_list() else {
|
||||
let Some(args) = args.list() else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_specific_argument_and_list(attr_span, &[sym::assert_eq, sym::debug]);
|
||||
return None;
|
||||
};
|
||||
|
||||
let arg = cx.expect_single(args)?;
|
||||
let Some(arg) = args.single() else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_single_argument(attr_span);
|
||||
return None;
|
||||
};
|
||||
|
||||
let mut fail_incorrect_argument =
|
||||
|span| cx.adcx().expected_specific_argument(span, &[sym::assert_eq, sym::debug]);
|
||||
@@ -171,6 +179,7 @@ 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;
|
||||
}
|
||||
@@ -179,6 +188,7 @@ 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)),
|
||||
@@ -193,11 +203,21 @@ pub(crate) struct TestRunnerParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for TestRunnerParser {
|
||||
const PATH: &[Symbol] = &[sym::test_runner];
|
||||
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 single = cx.expect_single_element_list(args, cx.attr_span)?;
|
||||
let Some(list) = args.list() else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_list(attr_span, args);
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(single) = list.single() else {
|
||||
cx.adcx().expected_single_argument(list.span);
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(meta) = single.meta_item() else {
|
||||
cx.adcx().expected_not_literal(single.span());
|
||||
@@ -212,6 +232,7 @@ pub(crate) struct RustcTestMarkerParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcTestMarkerParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_test_marker];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Const),
|
||||
Allow(Target::Fn),
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
use std::mem;
|
||||
|
||||
use super::prelude::*;
|
||||
use crate::attributes::{NoArgsAttributeParser, SingleAttributeParser};
|
||||
use crate::attributes::{NoArgsAttributeParser, OnDuplicate, SingleAttributeParser};
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::parser::ArgParser;
|
||||
use crate::target_checking::AllowedTargets;
|
||||
use crate::target_checking::Policy::{Allow, Warn};
|
||||
use crate::target_checking::{ALL_TARGETS, AllowedTargets};
|
||||
|
||||
pub(crate) struct RustcSkipDuringMethodDispatchParser;
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcSkipDuringMethodDispatchParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_skip_during_method_dispatch];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["array, boxed_slice"]);
|
||||
@@ -17,7 +18,11 @@ impl<S: Stage> SingleAttributeParser<S> for RustcSkipDuringMethodDispatchParser
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let mut array = false;
|
||||
let mut boxed_slice = false;
|
||||
let args = cx.expect_list(args, cx.attr_span)?;
|
||||
let Some(args) = args.list() else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_list(attr_span, args);
|
||||
return None;
|
||||
};
|
||||
if args.is_empty() {
|
||||
cx.adcx().expected_at_least_one_argument(args.span);
|
||||
return None;
|
||||
@@ -55,6 +60,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcSkipDuringMethodDispatchParser
|
||||
pub(crate) struct RustcParenSugarParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcParenSugarParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_paren_sugar];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcParenSugar;
|
||||
}
|
||||
@@ -64,6 +70,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcParenSugarParser {
|
||||
pub(crate) struct MarkerParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for MarkerParser {
|
||||
const PATH: &[Symbol] = &[sym::marker];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Trait),
|
||||
Warn(Target::Field),
|
||||
@@ -76,6 +83,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for MarkerParser {
|
||||
pub(crate) struct RustcDenyExplicitImplParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDenyExplicitImplParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_deny_explicit_impl];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcDenyExplicitImpl;
|
||||
}
|
||||
@@ -83,6 +91,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcDenyExplicitImplParser {
|
||||
pub(crate) struct RustcDynIncompatibleTraitParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcDynIncompatibleTraitParser {
|
||||
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::RustcDynIncompatibleTrait;
|
||||
}
|
||||
@@ -92,6 +101,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcDynIncompatibleTraitParser {
|
||||
pub(crate) struct RustcSpecializationTraitParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcSpecializationTraitParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_specialization_trait];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcSpecializationTrait;
|
||||
}
|
||||
@@ -99,6 +109,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcSpecializationTraitParser {
|
||||
pub(crate) struct RustcUnsafeSpecializationMarkerParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcUnsafeSpecializationMarkerParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_unsafe_specialization_marker];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcUnsafeSpecializationMarker;
|
||||
}
|
||||
@@ -108,6 +119,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcUnsafeSpecializationMarkerParse
|
||||
pub(crate) struct RustcCoinductiveParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcCoinductiveParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_coinductive];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcCoinductive;
|
||||
}
|
||||
@@ -115,6 +127,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcCoinductiveParser {
|
||||
pub(crate) struct RustcAllowIncoherentImplParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcAllowIncoherentImplParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_allow_incoherent_impl];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets =
|
||||
AllowedTargets::AllowList(&[Allow(Target::Method(MethodKind::Inherent))]);
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcAllowIncoherentImpl;
|
||||
@@ -123,7 +136,16 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcAllowIncoherentImplParser {
|
||||
pub(crate) struct FundamentalParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for FundamentalParser {
|
||||
const PATH: &[Symbol] = &[sym::fundamental];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets =
|
||||
AllowedTargets::AllowList(&[Allow(Target::Struct), Allow(Target::Trait)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::Fundamental;
|
||||
}
|
||||
|
||||
pub(crate) struct PointeeParser;
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for PointeeParser {
|
||||
const PATH: &[Symbol] = &[sym::pointee];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs`
|
||||
const CREATE: fn(Span) -> AttributeKind = AttributeKind::Pointee;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use std::num::IntErrorKind;
|
||||
|
||||
use rustc_ast::{LitKind, ast};
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_ast::attr::AttributeExt;
|
||||
use rustc_feature::is_builtin_attr_name;
|
||||
use rustc_hir::RustcVersion;
|
||||
use rustc_hir::limit::Limit;
|
||||
@@ -26,8 +27,8 @@ pub fn parse_version(s: Symbol) -> Option<RustcVersion> {
|
||||
Some(RustcVersion { major, minor, patch })
|
||||
}
|
||||
|
||||
pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
|
||||
attr.is_doc_comment() || attr.name().is_some_and(|name| is_builtin_attr_name(name))
|
||||
pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool {
|
||||
attr.is_doc_comment().is_some() || attr.name().is_some_and(|name| is_builtin_attr_name(name))
|
||||
}
|
||||
|
||||
/// Parse a single integer.
|
||||
@@ -40,7 +41,15 @@ pub(crate) fn parse_single_integer<S: Stage>(
|
||||
cx: &mut AcceptContext<'_, '_, S>,
|
||||
args: &ArgParser,
|
||||
) -> Option<u128> {
|
||||
let single = cx.expect_single_element_list(args, cx.attr_span)?;
|
||||
let Some(list) = args.list() else {
|
||||
let attr_span = cx.attr_span;
|
||||
cx.adcx().expected_list(attr_span, args);
|
||||
return None;
|
||||
};
|
||||
let Some(single) = list.single() else {
|
||||
cx.adcx().expected_single_argument(list.span);
|
||||
return None;
|
||||
};
|
||||
let Some(lit) = single.lit() else {
|
||||
cx.adcx().expected_integer_literal(single.span());
|
||||
return None;
|
||||
|
||||
@@ -7,8 +7,7 @@ use std::sync::LazyLock;
|
||||
|
||||
use private::Sealed;
|
||||
use rustc_ast::{AttrStyle, MetaItemLit, NodeId};
|
||||
use rustc_data_structures::sync::{DynSend, DynSync};
|
||||
use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level, MultiSpan};
|
||||
use rustc_errors::{Diag, Diagnostic, Level, MultiSpan};
|
||||
use rustc_feature::{AttrSuggestionStyle, AttributeTemplate};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
@@ -18,6 +17,7 @@ use rustc_session::Session;
|
||||
use rustc_session::lint::{Lint, LintId};
|
||||
use rustc_span::{ErrorGuaranteed, Span, Symbol};
|
||||
|
||||
use crate::AttributeParser;
|
||||
// Glob imports to avoid big, bitrotty import lists
|
||||
use crate::attributes::allow_unstable::*;
|
||||
use crate::attributes::autodiff::*;
|
||||
@@ -33,7 +33,6 @@ use crate::attributes::diagnostic::on_const::*;
|
||||
use crate::attributes::diagnostic::on_move::*;
|
||||
use crate::attributes::diagnostic::on_unimplemented::*;
|
||||
use crate::attributes::diagnostic::on_unknown::*;
|
||||
use crate::attributes::diagnostic::on_unmatch_args::*;
|
||||
use crate::attributes::doc::*;
|
||||
use crate::attributes::dummy::*;
|
||||
use crate::attributes::inline::*;
|
||||
@@ -60,14 +59,13 @@ use crate::attributes::stability::*;
|
||||
use crate::attributes::test_attrs::*;
|
||||
use crate::attributes::traits::*;
|
||||
use crate::attributes::transparency::*;
|
||||
use crate::attributes::{AttributeParser as _, AttributeSafety, Combine, Single, WithoutArgs};
|
||||
use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, RefPathParser};
|
||||
use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
|
||||
use crate::parser::{ArgParser, RefPathParser};
|
||||
use crate::session_diagnostics::{
|
||||
AttributeParseError, AttributeParseErrorReason, AttributeParseErrorSuggestions,
|
||||
ParsedDescription,
|
||||
};
|
||||
use crate::target_checking::AllowedTargets;
|
||||
use crate::{AttributeParser, EmitAttribute};
|
||||
type GroupType<S> = LazyLock<GroupTypeInner<S>>;
|
||||
|
||||
pub(super) struct GroupTypeInner<S: Stage> {
|
||||
@@ -78,13 +76,13 @@ pub(super) struct GroupTypeInnerAccept<S: Stage> {
|
||||
pub(super) template: AttributeTemplate,
|
||||
pub(super) accept_fn: AcceptFn<S>,
|
||||
pub(super) allowed_targets: AllowedTargets,
|
||||
pub(super) safety: AttributeSafety,
|
||||
pub(super) finalizer: FinalizeFn<S>,
|
||||
}
|
||||
|
||||
pub(crate) type AcceptFn<S> =
|
||||
Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, S>, &ArgParser) + Send + Sync>;
|
||||
pub(crate) type FinalizeFn<S> = fn(&mut FinalizeContext<'_, '_, S>) -> Option<AttributeKind>;
|
||||
pub(crate) type FinalizeFn<S> =
|
||||
Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, S>) -> Option<AttributeKind>>;
|
||||
|
||||
macro_rules! attribute_parsers {
|
||||
(
|
||||
@@ -128,12 +126,11 @@ macro_rules! attribute_parsers {
|
||||
accept_fn(s, cx, args)
|
||||
})
|
||||
}),
|
||||
safety: <$names as crate::attributes::AttributeParser<$stage>>::SAFETY,
|
||||
allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS,
|
||||
finalizer: |cx| {
|
||||
finalizer: Box::new(|cx| {
|
||||
let state = STATE_OBJECT.take();
|
||||
state.finalize(cx)
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
Entry::Occupied(_) => panic!("Attribute {path:?} has multiple accepters"),
|
||||
@@ -159,7 +156,6 @@ attribute_parsers!(
|
||||
OnMoveParser,
|
||||
OnUnimplementedParser,
|
||||
OnUnknownParser,
|
||||
OnUnmatchArgsParser,
|
||||
RustcAlignParser,
|
||||
RustcAlignStaticParser,
|
||||
RustcCguTestAttributeParser,
|
||||
@@ -183,7 +179,6 @@ attribute_parsers!(
|
||||
Combine<RustcThenThisWouldNeedParser>,
|
||||
Combine<TargetFeatureParser>,
|
||||
Combine<UnstableFeatureBoundParser>,
|
||||
Combine<UnstableRemovedParser>,
|
||||
// tidy-alphabetical-end
|
||||
|
||||
// tidy-alphabetical-start
|
||||
@@ -273,6 +268,7 @@ attribute_parsers!(
|
||||
Single<WithoutArgs<PanicHandlerParser>>,
|
||||
Single<WithoutArgs<PanicRuntimeParser>>,
|
||||
Single<WithoutArgs<PinV2Parser>>,
|
||||
Single<WithoutArgs<PointeeParser>>,
|
||||
Single<WithoutArgs<PreludeImportParser>>,
|
||||
Single<WithoutArgs<ProcMacroAttributeParser>>,
|
||||
Single<WithoutArgs<ProcMacroParser>>,
|
||||
@@ -318,7 +314,6 @@ attribute_parsers!(
|
||||
Single<WithoutArgs<RustcNoImplicitAutorefsParser>>,
|
||||
Single<WithoutArgs<RustcNoImplicitBoundsParser>>,
|
||||
Single<WithoutArgs<RustcNoMirInlineParser>>,
|
||||
Single<WithoutArgs<RustcNoWritableParser>>,
|
||||
Single<WithoutArgs<RustcNonConstTraitMethodParser>>,
|
||||
Single<WithoutArgs<RustcNonnullOptimizationGuaranteedParser>>,
|
||||
Single<WithoutArgs<RustcNounwindParser>>,
|
||||
@@ -463,34 +458,11 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
|
||||
/// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
|
||||
/// must be delayed until after HIR is built. This method will take care of the details of
|
||||
/// that.
|
||||
pub(crate) fn emit_lint(
|
||||
pub(crate) fn emit_lint<M: Into<MultiSpan>>(
|
||||
&mut self,
|
||||
lint: &'static Lint,
|
||||
kind: AttributeLintKind,
|
||||
span: impl Into<MultiSpan>,
|
||||
) {
|
||||
self.emit_lint_inner(lint, EmitAttribute::Static(kind), span);
|
||||
}
|
||||
|
||||
/// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
|
||||
/// must be delayed until after HIR is built. This method will take care of the details of
|
||||
/// that.
|
||||
pub(crate) fn emit_dyn_lint<
|
||||
F: for<'a> Fn(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + DynSend + DynSync + 'static,
|
||||
>(
|
||||
&mut self,
|
||||
lint: &'static Lint,
|
||||
callback: F,
|
||||
span: impl Into<MultiSpan>,
|
||||
) {
|
||||
self.emit_lint_inner(lint, EmitAttribute::Dynamic(Box::new(callback)), span);
|
||||
}
|
||||
|
||||
fn emit_lint_inner(
|
||||
&mut self,
|
||||
lint: &'static Lint,
|
||||
kind: EmitAttribute,
|
||||
span: impl Into<MultiSpan>,
|
||||
span: M,
|
||||
) {
|
||||
if !matches!(
|
||||
self.stage.should_emit(),
|
||||
@@ -502,15 +474,12 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
|
||||
}
|
||||
|
||||
pub(crate) fn warn_unused_duplicate(&mut self, used_span: Span, unused_span: Span) {
|
||||
self.emit_dyn_lint(
|
||||
self.emit_lint(
|
||||
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
|
||||
move |dcx, level| {
|
||||
rustc_errors::lints::UnusedDuplicate {
|
||||
this: unused_span,
|
||||
other: used_span,
|
||||
warning: false,
|
||||
}
|
||||
.into_diag(dcx, level)
|
||||
AttributeLintKind::UnusedDuplicate {
|
||||
this: unused_span,
|
||||
other: used_span,
|
||||
warning: false,
|
||||
},
|
||||
unused_span,
|
||||
)
|
||||
@@ -521,15 +490,12 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
|
||||
used_span: Span,
|
||||
unused_span: Span,
|
||||
) {
|
||||
self.emit_dyn_lint(
|
||||
self.emit_lint(
|
||||
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
|
||||
move |dcx, level| {
|
||||
rustc_errors::lints::UnusedDuplicate {
|
||||
this: unused_span,
|
||||
other: used_span,
|
||||
warning: true,
|
||||
}
|
||||
.into_diag(dcx, level)
|
||||
AttributeLintKind::UnusedDuplicate {
|
||||
this: unused_span,
|
||||
other: used_span,
|
||||
warning: true,
|
||||
},
|
||||
unused_span,
|
||||
)
|
||||
@@ -540,82 +506,6 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
pub(crate) fn adcx(&mut self) -> AttributeDiagnosticContext<'_, 'f, 'sess, S> {
|
||||
AttributeDiagnosticContext { ctx: self, custom_suggestions: Vec::new() }
|
||||
}
|
||||
|
||||
/// Asserts that this MetaItem is a list that contains a single element. Emits an error and
|
||||
/// returns `None` if it is not the case.
|
||||
///
|
||||
/// Some examples:
|
||||
///
|
||||
/// - In `#[allow(warnings)]`, `warnings` is returned
|
||||
/// - In `#[cfg_attr(docsrs, doc = "foo")]`, `None` is returned, "expected a single argument
|
||||
/// here" is emitted.
|
||||
/// - In `#[cfg()]`, `None` is returned, "expected an argument here" is emitted.
|
||||
///
|
||||
/// The provided span is used as a fallback for diagnostic generation in case `arg` does not
|
||||
/// contain any. It should be the span of the node that contains `arg`.
|
||||
pub(crate) fn expect_single_element_list<'arg>(
|
||||
&mut self,
|
||||
arg: &'arg ArgParser,
|
||||
span: Span,
|
||||
) -> Option<&'arg MetaItemOrLitParser> {
|
||||
let ArgParser::List(l) = arg else {
|
||||
self.adcx().expected_list(span, arg);
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(single) = l.as_single() else {
|
||||
self.adcx().expected_single_argument(l.span, l.len());
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(single)
|
||||
}
|
||||
|
||||
/// Asserts that an [`ArgParser`] is a list and returns it, or emits an error and returns
|
||||
/// `None`.
|
||||
///
|
||||
/// Some examples:
|
||||
///
|
||||
/// - `#[allow(clippy::complexity)]`: `(clippy::complexity)` is a list
|
||||
/// - `#[rustfmt::skip::macros(target_macro_name)]`: `(target_macro_name)` is a list
|
||||
///
|
||||
/// This is a higher-level (and harder to misuse) wrapper over [`ArgParser::as_list`]. That
|
||||
/// allows using `?` when the attribute parsing function allows it. You may still want to use
|
||||
/// [`ArgParser::as_list`] for the following reasons:
|
||||
///
|
||||
/// - You want to emit your own diagnostics (for instance, with [`SharedContext::emit_err`]).
|
||||
/// - The attribute can be parsed in multiple ways and it does not make sense to emit an error.
|
||||
pub(crate) fn expect_list<'arg>(
|
||||
&mut self,
|
||||
args: &'arg ArgParser,
|
||||
span: Span,
|
||||
) -> Option<&'arg MetaItemListParser> {
|
||||
let list = args.as_list();
|
||||
if list.is_none() {
|
||||
self.adcx().expected_list(span, args);
|
||||
}
|
||||
list
|
||||
}
|
||||
|
||||
/// Asserts that a [`MetaItemListParser`] contains a single element and returns it, or emits an
|
||||
/// error and returns `None`.
|
||||
///
|
||||
/// This is a higher-level (and harder to misuse) wrapper over [`MetaItemListParser::as_single`].
|
||||
/// That allows using `?` to early return. You may still want to use
|
||||
/// [`MetaItemListParser::as_single`] for the following reasons:
|
||||
///
|
||||
/// - You want to emit your own diagnostics (for instance, with [`SharedContext::emit_err`]).
|
||||
/// - The attribute can be parsed in multiple ways and it does not make sense to emit an error.
|
||||
pub(crate) fn expect_single<'arg>(
|
||||
&mut self,
|
||||
list: &'arg MetaItemListParser,
|
||||
) -> Option<&'arg MetaItemOrLitParser> {
|
||||
let single = list.as_single();
|
||||
if single.is_none() {
|
||||
self.adcx().expected_single_argument(list.span, list.len());
|
||||
}
|
||||
single
|
||||
}
|
||||
}
|
||||
|
||||
impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> {
|
||||
@@ -646,7 +536,7 @@ pub struct SharedContext<'p, 'sess, S: Stage> {
|
||||
|
||||
/// The second argument of the closure is a [`NodeId`] if `S` is `Early` and a [`HirId`] if `S`
|
||||
/// is `Late` and is the ID of the syntactical component this attribute was applied to.
|
||||
pub(crate) emit_lint: &'p mut dyn FnMut(LintId, MultiSpan, EmitAttribute),
|
||||
pub(crate) emit_lint: &'p mut dyn FnMut(LintId, MultiSpan, AttributeLintKind),
|
||||
}
|
||||
|
||||
/// Context given to every attribute parser during finalization.
|
||||
@@ -803,8 +693,6 @@ where
|
||||
)
|
||||
}
|
||||
|
||||
/// The provided span is used as a fallback in case `args` does not contain any. It should be
|
||||
/// the span of the node that contains `args`.
|
||||
pub(crate) fn expected_list(&mut self, span: Span, args: &ArgParser) -> ErrorGuaranteed {
|
||||
let span = match args {
|
||||
ArgParser::NoArgs => span,
|
||||
@@ -856,38 +744,19 @@ where
|
||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedNameValue(name))
|
||||
}
|
||||
|
||||
/// Emit an error that a `name = value` argument is missing in a list of name-value pairs.
|
||||
pub(crate) fn missing_name_value(&mut self, span: Span, name: Symbol) -> ErrorGuaranteed {
|
||||
self.emit_parse_error(span, AttributeParseErrorReason::MissingNameValue(name))
|
||||
}
|
||||
|
||||
/// Emit an error that a `name = value` pair was found where that name was already seen.
|
||||
pub(crate) fn duplicate_key(&mut self, span: Span, key: Symbol) -> ErrorGuaranteed {
|
||||
self.emit_parse_error(span, AttributeParseErrorReason::DuplicateKey(key))
|
||||
}
|
||||
|
||||
/// An error that should be emitted when a [`MetaItemOrLitParser`]
|
||||
/// An error that should be emitted when a [`MetaItemOrLitParser`](crate::parser::MetaItemOrLitParser)
|
||||
/// was expected *not* to be a literal, but instead a meta item.
|
||||
pub(crate) fn expected_not_literal(&mut self, span: Span) -> ErrorGuaranteed {
|
||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedNotLiteral)
|
||||
}
|
||||
|
||||
/// Signals that we expected exactly one argument and that we got either zero or two or more.
|
||||
/// The `provided_arguments` argument allows distinguishing between "expected an argument here"
|
||||
/// (when zero arguments are provided) and "expect a single argument here" (when two or more
|
||||
/// arguments are provided).
|
||||
pub(crate) fn expected_single_argument(
|
||||
&mut self,
|
||||
span: Span,
|
||||
provided_arguments: usize,
|
||||
) -> ErrorGuaranteed {
|
||||
let reason = if provided_arguments == 0 {
|
||||
AttributeParseErrorReason::ExpectedArgument
|
||||
} else {
|
||||
AttributeParseErrorReason::ExpectedSingleArgument
|
||||
};
|
||||
|
||||
self.emit_parse_error(span, reason)
|
||||
pub(crate) fn expected_single_argument(&mut self, span: Span) -> ErrorGuaranteed {
|
||||
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedSingleArgument)
|
||||
}
|
||||
|
||||
pub(crate) fn expected_at_least_one_argument(&mut self, span: Span) -> ErrorGuaranteed {
|
||||
@@ -944,18 +813,11 @@ where
|
||||
}
|
||||
|
||||
pub(crate) fn warn_empty_attribute(&mut self, span: Span) {
|
||||
let attr_path = self.attr_path.to_string();
|
||||
let attr_path = self.attr_path.clone().to_string();
|
||||
let valid_without_list = self.template.word;
|
||||
self.emit_dyn_lint(
|
||||
self.emit_lint(
|
||||
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
|
||||
move |dcx, level| {
|
||||
crate::errors::EmptyAttributeList {
|
||||
attr_span: span,
|
||||
attr_path: &attr_path,
|
||||
valid_without_list,
|
||||
}
|
||||
.into_diag(dcx, level)
|
||||
},
|
||||
AttributeLintKind::EmptyAttribute { first_span: span, attr_path, valid_without_list },
|
||||
span,
|
||||
);
|
||||
}
|
||||
@@ -970,12 +832,9 @@ where
|
||||
) {
|
||||
let suggestions = self.suggestions();
|
||||
let span = self.attr_span;
|
||||
self.emit_dyn_lint(
|
||||
self.emit_lint(
|
||||
lint,
|
||||
move |dcx, level| {
|
||||
crate::errors::IllFormedAttributeInput::new(&suggestions, None, help.as_deref())
|
||||
.into_diag(dcx, level)
|
||||
},
|
||||
AttributeLintKind::IllFormedAttributeInput { suggestions, docs: None, help },
|
||||
span,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use rustc_errors::{Applicability, DiagArgValue, MultiSpan};
|
||||
use rustc_errors::MultiSpan;
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
@@ -50,374 +50,3 @@ pub(crate) struct UnreachableCfgSelectPredicateWildcard {
|
||||
#[label("always matches")]
|
||||
pub wildcard_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("must be a name of an associated function")]
|
||||
pub(crate) struct MustBeNameOfAssociatedFunction {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("unsafe attribute used without unsafe")]
|
||||
pub(crate) struct UnsafeAttrOutsideUnsafeLint {
|
||||
#[label("usage of unsafe attribute")]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub suggestion: Option<crate::session_diagnostics::UnsafeAttrOutsideUnsafeSuggestion>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(
|
||||
"{$num_suggestions ->
|
||||
[1] attribute must be of the form {$suggestions}
|
||||
*[other] valid forms for the attribute are {$suggestions}
|
||||
}"
|
||||
)]
|
||||
pub(crate) struct IllFormedAttributeInput {
|
||||
pub num_suggestions: usize,
|
||||
pub suggestions: DiagArgValue,
|
||||
#[note("for more information, visit <{$docs}>")]
|
||||
pub has_docs: bool,
|
||||
pub docs: &'static str,
|
||||
#[subdiagnostic]
|
||||
help: Option<IllFormedAttributeInputHelp>,
|
||||
}
|
||||
|
||||
impl IllFormedAttributeInput {
|
||||
pub(crate) fn new(
|
||||
suggestions: &[String],
|
||||
docs: Option<&'static str>,
|
||||
help: Option<&str>,
|
||||
) -> Self {
|
||||
Self {
|
||||
num_suggestions: suggestions.len(),
|
||||
suggestions: DiagArgValue::StrListSepByAnd(
|
||||
suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
|
||||
),
|
||||
has_docs: docs.is_some(),
|
||||
docs: docs.unwrap_or(""),
|
||||
help: help.map(|h| IllFormedAttributeInputHelp { lint: h.to_string() }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[help(
|
||||
"if you meant to silence a warning, consider using #![allow({$lint})] or #![expect({$lint})]"
|
||||
)]
|
||||
struct IllFormedAttributeInputHelp {
|
||||
pub lint: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("unused attribute")]
|
||||
#[note(
|
||||
"{$valid_without_list ->
|
||||
[true] using `{$attr_path}` with an empty list is equivalent to not using a list at all
|
||||
*[other] using `{$attr_path}` with an empty list has no effect
|
||||
}"
|
||||
)]
|
||||
pub(crate) struct EmptyAttributeList<'a> {
|
||||
#[suggestion(
|
||||
"{$valid_without_list ->
|
||||
[true] remove these parentheses
|
||||
*[other] remove this attribute
|
||||
}",
|
||||
code = "",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub attr_span: Span,
|
||||
pub attr_path: &'a str,
|
||||
pub valid_without_list: bool,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`#[{$name}]` attribute cannot be used on {$target}")]
|
||||
#[warning(
|
||||
"this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!"
|
||||
)]
|
||||
#[help("`#[{$name}]` can {$only}be applied to {$applied}")]
|
||||
pub(crate) struct InvalidTargetLint {
|
||||
pub name: String,
|
||||
pub target: &'static str,
|
||||
pub applied: DiagArgValue,
|
||||
pub only: &'static str,
|
||||
#[suggestion(
|
||||
"remove the attribute",
|
||||
code = "",
|
||||
applicability = "machine-applicable",
|
||||
style = "tool-only"
|
||||
)]
|
||||
pub attr_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(
|
||||
"{$is_used_as_inner ->
|
||||
[false] crate-level attribute should be an inner attribute: add an exclamation mark: `#![{$name}]`
|
||||
*[other] the `#![{$name}]` attribute can only be used at the crate root
|
||||
}"
|
||||
)]
|
||||
pub(crate) struct InvalidAttrStyle<'a> {
|
||||
pub name: &'a str,
|
||||
pub is_used_as_inner: bool,
|
||||
#[note("this attribute does not have an `!`, which means it is applied to this {$target}")]
|
||||
pub target_span: Option<Span>,
|
||||
pub target: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("doc alias is duplicated")]
|
||||
pub(crate) struct DocAliasDuplicated {
|
||||
#[label("first defined here")]
|
||||
pub first_definition: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("only `hide` or `show` are allowed in `#[doc(auto_cfg(...))]`")]
|
||||
pub(crate) struct DocAutoCfgExpectsHideOrShow;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("there exists a built-in attribute with the same name")]
|
||||
pub(crate) struct AmbiguousDeriveHelpers;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`#![doc(auto_cfg({$attr_name}(...)))]` only accepts identifiers or key/value items")]
|
||||
pub(crate) struct DocAutoCfgHideShowUnexpectedItem {
|
||||
pub attr_name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`#![doc(auto_cfg({$attr_name}(...)))]` expects a list of items")]
|
||||
pub(crate) struct DocAutoCfgHideShowExpectsList {
|
||||
pub attr_name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("unknown `doc` attribute `include`")]
|
||||
pub(crate) struct DocUnknownInclude {
|
||||
pub inner: &'static str,
|
||||
pub value: Symbol,
|
||||
#[suggestion(
|
||||
"use `doc = include_str!` instead",
|
||||
code = "#{inner}[doc = include_str!(\"{value}\")]"
|
||||
)]
|
||||
pub sugg: (Span, Applicability),
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("unknown `doc` attribute `spotlight`")]
|
||||
#[note("`doc(spotlight)` was renamed to `doc(notable_trait)`")]
|
||||
#[note("`doc(spotlight)` is now a no-op")]
|
||||
pub(crate) struct DocUnknownSpotlight {
|
||||
#[suggestion(
|
||||
"use `notable_trait` instead",
|
||||
style = "short",
|
||||
applicability = "machine-applicable",
|
||||
code = "notable_trait"
|
||||
)]
|
||||
pub sugg_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("unknown `doc` attribute `{$name}`")]
|
||||
#[note(
|
||||
"`doc` attribute `{$name}` no longer functions; see issue #44136 <https://github.com/rust-lang/rust/issues/44136>"
|
||||
)]
|
||||
#[note("`doc({$name})` is now a no-op")]
|
||||
pub(crate) struct DocUnknownPasses {
|
||||
pub name: Symbol,
|
||||
#[label("no longer functions")]
|
||||
pub note_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("unknown `doc` attribute `plugins`")]
|
||||
#[note(
|
||||
"`doc` attribute `plugins` no longer functions; see issue #44136 <https://github.com/rust-lang/rust/issues/44136> and CVE-2018-1000622 <https://nvd.nist.gov/vuln/detail/CVE-2018-1000622>"
|
||||
)]
|
||||
#[note("`doc(plugins)` is now a no-op")]
|
||||
pub(crate) struct DocUnknownPlugins {
|
||||
#[label("no longer functions")]
|
||||
pub label_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("unknown `doc` attribute `{$name}`")]
|
||||
pub(crate) struct DocUnknownAny {
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("expected boolean for `#[doc(auto_cfg = ...)]`")]
|
||||
pub(crate) struct DocAutoCfgWrongLiteral;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`#[doc(test(...)]` takes a list of attributes")]
|
||||
pub(crate) struct DocTestTakesList;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("unknown `doc(test)` attribute `{$name}`")]
|
||||
pub(crate) struct DocTestUnknown {
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`#![doc(test(...)]` does not take a literal")]
|
||||
pub(crate) struct DocTestLiteral;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("this attribute can only be applied at the crate level")]
|
||||
#[note(
|
||||
"read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information"
|
||||
)]
|
||||
pub(crate) struct AttrCrateLevelOnly;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`#[diagnostic::do_not_recommend]` does not expect any arguments")]
|
||||
pub(crate) struct DoNotRecommendDoesNotExpectArgs;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("invalid `crate_type` value")]
|
||||
pub(crate) struct UnknownCrateTypes {
|
||||
#[subdiagnostic]
|
||||
pub sugg: Option<UnknownCrateTypesSuggestion>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion("did you mean", code = r#""{snippet}""#, applicability = "maybe-incorrect")]
|
||||
pub(crate) struct UnknownCrateTypesSuggestion {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub snippet: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`#[diagnostic::on_const]` can only be applied to non-const trait implementations")]
|
||||
pub(crate) struct DiagnosticOnConstOnlyForTraitImpls {
|
||||
#[label("not a trait implementation")]
|
||||
pub target_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`#[diagnostic::on_move]` can only be applied to enums, structs or unions")]
|
||||
pub(crate) struct DiagnosticOnMoveOnlyForAdt;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`#[diagnostic::on_unimplemented]` can only be applied to trait definitions")]
|
||||
pub(crate) struct DiagnosticOnUnimplementedOnlyForTraits;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`#[diagnostic::on_unknown]` can only be applied to `use` statements")]
|
||||
pub(crate) struct DiagnosticOnUnknownOnlyForImports {
|
||||
#[label("not an import")]
|
||||
pub target_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`#[diagnostic::on_unmatch_args]` can only be applied to macro definitions")]
|
||||
pub(crate) struct DiagnosticOnUnmatchArgsOnlyForMacros;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`#[diagnostic::do_not_recommend]` can only be placed on trait implementations")]
|
||||
pub(crate) struct IncorrectDoNotRecommendLocation {
|
||||
#[label("not a trait implementation")]
|
||||
pub target_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("malformed `doc` attribute input")]
|
||||
#[warning(
|
||||
"this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!"
|
||||
)]
|
||||
pub(crate) struct MalformedDoc;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("didn't expect any arguments here")]
|
||||
#[warning(
|
||||
"this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!"
|
||||
)]
|
||||
pub(crate) struct ExpectedNoArgs;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("expected this to be of the form `... = \"...\"`")]
|
||||
#[warning(
|
||||
"this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!"
|
||||
)]
|
||||
pub(crate) struct ExpectedNameValue;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("malformed `{$attribute}` attribute")]
|
||||
#[help("{$options}")]
|
||||
pub(crate) struct MalFormedDiagnosticAttributeLint {
|
||||
pub attribute: &'static str,
|
||||
pub options: &'static str,
|
||||
#[label("invalid option found here")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("{$description}")]
|
||||
pub(crate) struct WrappedParserError<'a> {
|
||||
pub description: &'a str,
|
||||
#[label("{$label}")]
|
||||
pub span: Span,
|
||||
pub label: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`{$option_name}` is ignored due to previous definition of `{$option_name}`")]
|
||||
pub(crate) struct IgnoredDiagnosticOption {
|
||||
pub option_name: Symbol,
|
||||
#[label("`{$option_name}` is first declared here")]
|
||||
pub first_span: Span,
|
||||
#[label("`{$option_name}` is later redundantly declared here")]
|
||||
pub later_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("missing options for `{$attribute}` attribute")]
|
||||
#[help("{$options}")]
|
||||
pub(crate) struct MissingOptionsForDiagnosticAttribute {
|
||||
pub attribute: &'static str,
|
||||
pub options: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("expected a literal or missing delimiter")]
|
||||
#[help(
|
||||
"only literals are allowed as values for the `message`, `note` and `label` options. These options must be separated by a comma"
|
||||
)]
|
||||
pub(crate) struct NonMetaItemDiagnosticAttribute;
|
||||
|
||||
#[derive(Diagnostic, Clone, Copy)]
|
||||
pub(crate) enum FormatWarning {
|
||||
#[diag("positional arguments are not permitted in diagnostic attributes")]
|
||||
#[help("you can print empty braces by escaping them")]
|
||||
PositionalArgument {
|
||||
#[label("remove this format argument")]
|
||||
span: Span,
|
||||
},
|
||||
|
||||
#[diag("indexed format arguments are not permitted in diagnostic attributes")]
|
||||
IndexedArgument {
|
||||
#[label("remove this format argument")]
|
||||
span: Span,
|
||||
},
|
||||
|
||||
#[diag("format specifiers are not permitted in diagnostic attributes")]
|
||||
InvalidSpecifier {
|
||||
#[label("remove this format specifier")]
|
||||
span: Span,
|
||||
},
|
||||
|
||||
#[diag("this format argument is not allowed in `#[{$attr}]`")]
|
||||
#[note("{$allowed}")]
|
||||
DisallowedPlaceholder {
|
||||
#[label("remove this format argument")]
|
||||
span: Span,
|
||||
attr: &'static str,
|
||||
allowed: &'static str,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -2,9 +2,8 @@ use std::convert::identity;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::token::DocFragmentKind;
|
||||
use rustc_ast::{AttrItemKind, AttrStyle, CRATE_NODE_ID, NodeId, Safety};
|
||||
use rustc_data_structures::sync::{DynSend, DynSync};
|
||||
use rustc_errors::{Diag, DiagCtxtHandle, Level, MultiSpan};
|
||||
use rustc_ast::{AttrItemKind, AttrStyle, NodeId, Safety};
|
||||
use rustc_errors::{DiagCtxtHandle, MultiSpan};
|
||||
use rustc_feature::{AttributeTemplate, Features};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
@@ -13,22 +12,12 @@ use rustc_session::Session;
|
||||
use rustc_session::lint::LintId;
|
||||
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
|
||||
|
||||
use crate::attributes::AttributeSafety;
|
||||
use crate::context::{AcceptContext, FinalizeContext, FinalizeFn, SharedContext, Stage};
|
||||
use crate::early_parsed::{EARLY_PARSED_ATTRIBUTES, EarlyParsedState};
|
||||
use crate::parser::{AllowExprMetavar, ArgParser, PathParser, RefPathParser};
|
||||
use crate::session_diagnostics::ParsedDescription;
|
||||
use crate::{Early, Late, OmitDoc, ShouldEmit};
|
||||
|
||||
pub enum EmitAttribute {
|
||||
Static(AttributeLintKind),
|
||||
Dynamic(
|
||||
Box<
|
||||
dyn for<'a> Fn(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + DynSend + DynSync + 'static,
|
||||
>,
|
||||
),
|
||||
}
|
||||
|
||||
/// Context created once, for example as part of the ast lowering
|
||||
/// context, through which all attributes can be lowered.
|
||||
pub struct AttributeParser<'sess, S: Stage = Late> {
|
||||
@@ -62,16 +51,18 @@ impl<'sess> AttributeParser<'sess, Early> {
|
||||
sess: &'sess Session,
|
||||
attrs: &[ast::Attribute],
|
||||
sym: &'static [Symbol],
|
||||
target_span: Span,
|
||||
target_node_id: NodeId,
|
||||
features: Option<&'sess Features>,
|
||||
) -> Option<Attribute> {
|
||||
Self::parse_limited_should_emit(
|
||||
sess,
|
||||
attrs,
|
||||
sym,
|
||||
// Because we're not emitting warnings/errors, the target should not matter
|
||||
DUMMY_SP,
|
||||
CRATE_NODE_ID,
|
||||
Target::Crate,
|
||||
None,
|
||||
target_span,
|
||||
target_node_id,
|
||||
Target::Crate, // Does not matter, we're not going to emit errors anyways
|
||||
features,
|
||||
ShouldEmit::Nothing,
|
||||
)
|
||||
}
|
||||
@@ -127,14 +118,7 @@ impl<'sess> AttributeParser<'sess, Early> {
|
||||
target,
|
||||
OmitDoc::Skip,
|
||||
std::convert::identity,
|
||||
|lint_id, span, kind| match kind {
|
||||
EmitAttribute::Static(kind) => {
|
||||
sess.psess.buffer_lint(lint_id.lint, span, target_node_id, kind)
|
||||
}
|
||||
EmitAttribute::Dynamic(callback) => {
|
||||
sess.psess.dyn_buffer_lint(lint_id.lint, span, target_node_id, callback)
|
||||
}
|
||||
},
|
||||
|lint_id, span, kind| sess.psess.buffer_lint(lint_id.lint, span, target_node_id, kind),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -151,7 +135,6 @@ impl<'sess> AttributeParser<'sess, Early> {
|
||||
parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser) -> Option<T>,
|
||||
template: &AttributeTemplate,
|
||||
allow_expr_metavar: AllowExprMetavar,
|
||||
expected_safety: AttributeSafety,
|
||||
) -> Option<T> {
|
||||
let ast::AttrKind::Normal(normal_attr) = &attr.kind else {
|
||||
panic!("parse_single called on a doc attr")
|
||||
@@ -174,7 +157,6 @@ impl<'sess> AttributeParser<'sess, Early> {
|
||||
attr.style,
|
||||
path,
|
||||
Some(normal_attr.item.unsafety),
|
||||
expected_safety,
|
||||
ParsedDescription::Attribute,
|
||||
target_span,
|
||||
target_node_id,
|
||||
@@ -196,7 +178,6 @@ impl<'sess> AttributeParser<'sess, Early> {
|
||||
attr_style: AttrStyle,
|
||||
attr_path: AttrPath,
|
||||
attr_safety: Option<Safety>,
|
||||
expected_safety: AttributeSafety,
|
||||
parsed_description: ParsedDescription,
|
||||
target_span: Span,
|
||||
target_node_id: NodeId,
|
||||
@@ -214,22 +195,11 @@ impl<'sess> AttributeParser<'sess, Early> {
|
||||
sess,
|
||||
stage: Early { emit_errors },
|
||||
};
|
||||
let mut emit_lint = |lint_id: LintId, span: MultiSpan, kind: EmitAttribute| match kind {
|
||||
EmitAttribute::Static(kind) => {
|
||||
sess.psess.buffer_lint(lint_id.lint, span, target_node_id, kind)
|
||||
}
|
||||
EmitAttribute::Dynamic(callback) => {
|
||||
sess.psess.dyn_buffer_lint(lint_id.lint, span, target_node_id, callback)
|
||||
}
|
||||
let mut emit_lint = |lint_id: LintId, span: MultiSpan, kind: AttributeLintKind| {
|
||||
sess.psess.buffer_lint(lint_id.lint, span, target_node_id, kind)
|
||||
};
|
||||
if let Some(safety) = attr_safety {
|
||||
parser.check_attribute_safety(
|
||||
&attr_path,
|
||||
inner_span,
|
||||
safety,
|
||||
expected_safety,
|
||||
&mut emit_lint,
|
||||
);
|
||||
parser.check_attribute_safety(&attr_path, inner_span, safety, &mut emit_lint)
|
||||
}
|
||||
let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
|
||||
shared: SharedContext {
|
||||
@@ -286,7 +256,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
||||
target: Target,
|
||||
omit_doc: OmitDoc,
|
||||
lower_span: impl Copy + Fn(Span) -> Span,
|
||||
mut emit_lint: impl FnMut(LintId, MultiSpan, EmitAttribute),
|
||||
mut emit_lint: impl FnMut(LintId, MultiSpan, AttributeLintKind),
|
||||
) -> Vec<Attribute> {
|
||||
let mut attributes = Vec::new();
|
||||
// We store the attributes we intend to discard at the end of this function in order to
|
||||
@@ -297,7 +267,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
||||
let mut attr_paths: Vec<RefPathParser<'_>> = Vec::new();
|
||||
let mut early_parsed_state = EarlyParsedState::default();
|
||||
|
||||
let mut finalizers: Vec<FinalizeFn<S>> = Vec::with_capacity(attrs.len());
|
||||
let mut finalizers: Vec<&FinalizeFn<S>> = Vec::with_capacity(attrs.len());
|
||||
|
||||
for attr in attrs {
|
||||
// If we're only looking for a single attribute, skip all the ones we don't care about.
|
||||
@@ -344,18 +314,17 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
||||
}
|
||||
};
|
||||
|
||||
self.check_attribute_safety(
|
||||
&attr_path,
|
||||
lower_span(n.item.span()),
|
||||
n.item.unsafety,
|
||||
&mut emit_lint,
|
||||
);
|
||||
|
||||
let parts =
|
||||
n.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>();
|
||||
|
||||
if let Some(accept) = S::parsers().accepters.get(parts.as_slice()) {
|
||||
self.check_attribute_safety(
|
||||
&attr_path,
|
||||
lower_span(n.item.span()),
|
||||
n.item.unsafety,
|
||||
accept.safety,
|
||||
&mut emit_lint,
|
||||
);
|
||||
|
||||
let Some(args) = ArgParser::from_attr_args(
|
||||
args,
|
||||
&parts,
|
||||
@@ -413,7 +382,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
||||
};
|
||||
|
||||
(accept.accept_fn)(&mut cx, &args);
|
||||
finalizers.push(accept.finalizer);
|
||||
finalizers.push(&accept.finalizer);
|
||||
|
||||
if !matches!(cx.stage.should_emit(), ShouldEmit::Nothing) {
|
||||
Self::check_target(&accept.allowed_targets, target, &mut cx);
|
||||
@@ -428,14 +397,6 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
||||
span: attr_span,
|
||||
};
|
||||
|
||||
self.check_attribute_safety(
|
||||
&attr_path,
|
||||
lower_span(n.item.span()),
|
||||
n.item.unsafety,
|
||||
AttributeSafety::Normal,
|
||||
&mut emit_lint,
|
||||
);
|
||||
|
||||
if !matches!(self.stage.should_emit(), ShouldEmit::Nothing)
|
||||
&& target == Target::Crate
|
||||
{
|
||||
|
||||
@@ -106,12 +106,11 @@ mod session_diagnostics;
|
||||
mod target_checking;
|
||||
pub mod validate_attr;
|
||||
|
||||
pub use attributes::AttributeSafety;
|
||||
pub use attributes::cfg::{
|
||||
CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg, parse_cfg_attr, parse_cfg_entry,
|
||||
};
|
||||
pub use attributes::cfg_select::*;
|
||||
pub use attributes::util::{is_builtin_attr, parse_version};
|
||||
pub use context::{Early, Late, OmitDoc, ShouldEmit};
|
||||
pub use interface::{AttributeParser, EmitAttribute};
|
||||
pub use interface::AttributeParser;
|
||||
pub use session_diagnostics::ParsedDescription;
|
||||
|
||||
@@ -176,7 +176,7 @@ impl ArgParser {
|
||||
///
|
||||
/// - `#[allow(clippy::complexity)]`: `(clippy::complexity)` is a list
|
||||
/// - `#[rustfmt::skip::macros(target_macro_name)]`: `(target_macro_name)` is a list
|
||||
pub fn as_list(&self) -> Option<&MetaItemListParser> {
|
||||
pub fn list(&self) -> Option<&MetaItemListParser> {
|
||||
match self {
|
||||
Self::List(l) => Some(l),
|
||||
Self::NameValue(_) | Self::NoArgs => None,
|
||||
@@ -255,7 +255,6 @@ impl MetaItemOrLitParser {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(scrabsha): once #155696 is merged, update this and mention the higher-level APIs.
|
||||
/// Utility that deconstructs a MetaItem into usable parts.
|
||||
///
|
||||
/// MetaItems are syntactically extremely flexible, but specific attributes want to parse
|
||||
@@ -264,7 +263,7 @@ impl MetaItemOrLitParser {
|
||||
/// MetaItems consist of some path, and some args. The args could be empty. In other words:
|
||||
///
|
||||
/// - `name` -> args are empty
|
||||
/// - `name(...)` -> args are a [`list`](ArgParser::as_list), which is the bit between the parentheses
|
||||
/// - `name(...)` -> args are a [`list`](ArgParser::list), which is the bit between the parentheses
|
||||
/// - `name = value`-> arg is [`name_value`](ArgParser::name_value), where the argument is the
|
||||
/// `= value` part
|
||||
///
|
||||
@@ -695,7 +694,7 @@ impl MetaItemListParser {
|
||||
/// Returns Some if the list contains only a single element.
|
||||
///
|
||||
/// Inside the Some is the parser to parse this single element.
|
||||
pub fn as_single(&self) -> Option<&MetaItemOrLitParser> {
|
||||
pub fn single(&self) -> Option<&MetaItemOrLitParser> {
|
||||
let mut iter = self.mixed();
|
||||
iter.next().filter(|_| iter.next().is_none())
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
use rustc_ast::Safety;
|
||||
use rustc_errors::{Diagnostic, MultiSpan};
|
||||
use rustc_errors::MultiSpan;
|
||||
use rustc_feature::{AttributeSafety, BUILTIN_ATTRIBUTE_MAP};
|
||||
use rustc_hir::AttrPath;
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_session::lint::LintId;
|
||||
use rustc_session::lint::builtin::UNSAFE_ATTR_OUTSIDE_UNSAFE;
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::attributes::AttributeSafety;
|
||||
use crate::context::Stage;
|
||||
use crate::{AttributeParser, EmitAttribute, ShouldEmit, errors};
|
||||
use crate::{AttributeParser, ShouldEmit};
|
||||
|
||||
impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
||||
pub fn check_attribute_safety(
|
||||
@@ -15,23 +16,28 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
||||
attr_path: &AttrPath,
|
||||
attr_span: Span,
|
||||
attr_safety: Safety,
|
||||
expected_safety: AttributeSafety,
|
||||
emit_lint: &mut impl FnMut(LintId, MultiSpan, EmitAttribute),
|
||||
emit_lint: &mut impl FnMut(LintId, MultiSpan, AttributeLintKind),
|
||||
) {
|
||||
if matches!(self.stage.should_emit(), ShouldEmit::Nothing) {
|
||||
return;
|
||||
}
|
||||
|
||||
match (expected_safety, attr_safety) {
|
||||
let name = (attr_path.segments.len() == 1).then_some(attr_path.segments[0]);
|
||||
|
||||
// FIXME: We should retrieve this information from the attribute parsers instead of from `BUILTIN_ATTRIBUTE_MAP`
|
||||
let builtin_attr_info = name.and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name));
|
||||
let builtin_attr_safety = builtin_attr_info.map(|x| x.safety);
|
||||
|
||||
match (builtin_attr_safety, attr_safety) {
|
||||
// - Unsafe builtin attribute
|
||||
// - User wrote `#[unsafe(..)]`, which is permitted on any edition
|
||||
(AttributeSafety::Unsafe { .. }, Safety::Unsafe(..)) => {
|
||||
(Some(AttributeSafety::Unsafe { .. }), Safety::Unsafe(..)) => {
|
||||
// OK
|
||||
}
|
||||
|
||||
// - Unsafe builtin attribute
|
||||
// - User did not write `#[unsafe(..)]`
|
||||
(AttributeSafety::Unsafe { unsafe_since }, Safety::Default) => {
|
||||
(Some(AttributeSafety::Unsafe { unsafe_since }), Safety::Default) => {
|
||||
let path_span = attr_path.span;
|
||||
|
||||
// If the `attr_item`'s span is not from a macro, then just suggest
|
||||
@@ -79,24 +85,18 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
||||
emit_lint(
|
||||
LintId::of(UNSAFE_ATTR_OUTSIDE_UNSAFE),
|
||||
path_span.into(),
|
||||
EmitAttribute::Dynamic(Box::new(move |dcx, level| {
|
||||
errors::UnsafeAttrOutsideUnsafeLint {
|
||||
span: path_span,
|
||||
suggestion: not_from_proc_macro
|
||||
.then(|| (diag_span.shrink_to_lo(), diag_span.shrink_to_hi()))
|
||||
.map(|(left, right)| {
|
||||
crate::session_diagnostics::UnsafeAttrOutsideUnsafeSuggestion { left, right }
|
||||
}),
|
||||
}
|
||||
.into_diag(dcx, level)
|
||||
})),
|
||||
AttributeLintKind::UnsafeAttrOutsideUnsafe {
|
||||
attribute_name_span: path_span,
|
||||
sugg_spans: not_from_proc_macro
|
||||
.then(|| (diag_span.shrink_to_lo(), diag_span.shrink_to_hi())),
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// - Normal builtin attribute
|
||||
// - Writing `#[unsafe(..)]` is not permitted on normal builtin attributes
|
||||
(AttributeSafety::Normal, Safety::Unsafe(unsafe_span)) => {
|
||||
(None | Some(AttributeSafety::Normal), Safety::Unsafe(unsafe_span)) => {
|
||||
self.stage.emit_err(
|
||||
self.sess,
|
||||
crate::session_diagnostics::InvalidAttrUnsafe {
|
||||
@@ -108,11 +108,14 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
||||
|
||||
// - Normal builtin attribute
|
||||
// - No explicit `#[unsafe(..)]` written.
|
||||
(AttributeSafety::Normal, Safety::Default) => {
|
||||
(None | Some(AttributeSafety::Normal), Safety::Default) => {
|
||||
// OK
|
||||
}
|
||||
|
||||
(_, Safety::Safe(..)) => {
|
||||
(
|
||||
Some(AttributeSafety::Unsafe { .. } | AttributeSafety::Normal) | None,
|
||||
Safety::Safe(..),
|
||||
) => {
|
||||
self.sess.dcx().span_delayed_bug(
|
||||
attr_span,
|
||||
"`check_attribute_safety` does not expect `Safety::Safe` on attributes",
|
||||
|
||||
@@ -557,7 +557,6 @@ pub(crate) enum AttributeParseErrorReason<'a> {
|
||||
upper_bound: isize,
|
||||
},
|
||||
ExpectedAtLeastOneArgument,
|
||||
ExpectedArgument,
|
||||
ExpectedSingleArgument,
|
||||
ExpectedList,
|
||||
ExpectedListOrNoArgs,
|
||||
@@ -568,7 +567,6 @@ pub(crate) enum AttributeParseErrorReason<'a> {
|
||||
ExpectedNonEmptyStringLiteral,
|
||||
ExpectedNotLiteral,
|
||||
ExpectedNameValue(Option<Symbol>),
|
||||
MissingNameValue(Symbol),
|
||||
DuplicateKey(Symbol),
|
||||
ExpectedSpecificArgument {
|
||||
possibilities: &'a [Symbol],
|
||||
@@ -775,10 +773,6 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
|
||||
diag.span_label(self.span, "expected a single argument here");
|
||||
diag.code(E0805);
|
||||
}
|
||||
AttributeParseErrorReason::ExpectedArgument => {
|
||||
diag.span_label(self.span, "expected an argument here");
|
||||
diag.code(E0805);
|
||||
}
|
||||
AttributeParseErrorReason::ExpectedAtLeastOneArgument => {
|
||||
diag.span_label(self.span, "expected at least 1 argument here");
|
||||
}
|
||||
@@ -824,9 +818,6 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
|
||||
format!("expected this to be of the form `{name} = \"...\"`"),
|
||||
);
|
||||
}
|
||||
AttributeParseErrorReason::MissingNameValue(name) => {
|
||||
diag.span_label(self.span, format!("missing argument `{name} = \"...\"`"));
|
||||
}
|
||||
AttributeParseErrorReason::ExpectedSpecificArgument {
|
||||
possibilities,
|
||||
strings,
|
||||
@@ -1137,22 +1128,3 @@ pub(crate) struct UnstableAttrForAlreadyStableFeature {
|
||||
#[label("the stability attribute annotates this item")]
|
||||
pub item_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("invalid Mach-O section specifier")]
|
||||
pub(crate) struct InvalidMachoSection {
|
||||
#[primary_span]
|
||||
#[label("not a valid Mach-O section specifier")]
|
||||
pub name_span: Span,
|
||||
#[subdiagnostic]
|
||||
pub reason: InvalidMachoSectionReason,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum InvalidMachoSectionReason {
|
||||
#[note("a Mach-O section specifier requires a segment and a section, separated by a comma")]
|
||||
#[help("an example of a valid Mach-O section specifier is `__TEXT,__cstring`")]
|
||||
MissingSection,
|
||||
#[note("section name `{$section}` is longer than 16 bytes")]
|
||||
SectionTooLong { section: String },
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use rustc_ast::AttrStyle;
|
||||
use rustc_errors::{DiagArgValue, Diagnostic, MultiSpan, StashKey};
|
||||
use rustc_errors::{DiagArgValue, MultiSpan, StashKey};
|
||||
use rustc_feature::Features;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_hir::{AttrItem, Attribute, MethodKind, Target};
|
||||
use rustc_span::{BytePos, Span, Symbol, sym};
|
||||
|
||||
use crate::AttributeParser;
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::errors::{
|
||||
InvalidAttrAtCrateLevel, InvalidTargetLint, ItemFollowingInnerAttr,
|
||||
UnsupportedAttributesInWhere,
|
||||
InvalidAttrAtCrateLevel, ItemFollowingInnerAttr, UnsupportedAttributesInWhere,
|
||||
};
|
||||
use crate::session_diagnostics::InvalidTarget;
|
||||
use crate::target_checking::Policy::Allow;
|
||||
@@ -142,19 +142,14 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
||||
};
|
||||
|
||||
let attr_span = cx.attr_span;
|
||||
cx.emit_dyn_lint(
|
||||
cx.emit_lint(
|
||||
lint,
|
||||
move |dcx, level| {
|
||||
InvalidTargetLint {
|
||||
name: name.to_string(),
|
||||
target: target.plural_name(),
|
||||
only: if only { "only " } else { "" },
|
||||
applied: DiagArgValue::StrListSepByAnd(
|
||||
applied.iter().map(|i| Cow::Owned(i.to_string())).collect(),
|
||||
),
|
||||
attr_span,
|
||||
}
|
||||
.into_diag(dcx, level)
|
||||
AttributeLintKind::InvalidTarget {
|
||||
name: name.to_string(),
|
||||
target: target.plural_name(),
|
||||
only: if only { "only " } else { "" },
|
||||
applied,
|
||||
attr_span,
|
||||
},
|
||||
attr_span,
|
||||
);
|
||||
@@ -181,24 +176,15 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
||||
return;
|
||||
}
|
||||
|
||||
let name = cx.attr_path.to_string();
|
||||
let is_used_as_inner = cx.attr_style == AttrStyle::Inner;
|
||||
let target_span = cx.target_span;
|
||||
let kind = AttributeLintKind::InvalidStyle {
|
||||
name: cx.attr_path.to_string(),
|
||||
is_used_as_inner: cx.attr_style == AttrStyle::Inner,
|
||||
target: target.name(),
|
||||
target_span: cx.target_span,
|
||||
};
|
||||
let attr_span = cx.attr_span;
|
||||
|
||||
cx.emit_dyn_lint(
|
||||
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
|
||||
move |dcx, level| {
|
||||
crate::errors::InvalidAttrStyle {
|
||||
name: &name,
|
||||
is_used_as_inner,
|
||||
target_span: (!is_used_as_inner).then_some(target_span),
|
||||
target: target.name(),
|
||||
}
|
||||
.into_diag(dcx, level)
|
||||
},
|
||||
attr_span,
|
||||
);
|
||||
cx.emit_lint(rustc_session::lint::builtin::UNUSED_ATTRIBUTES, kind, attr_span);
|
||||
}
|
||||
|
||||
// FIXME: Fix "Cannot determine resolution" error and remove built-in macros
|
||||
|
||||
@@ -8,9 +8,10 @@ use rustc_ast::tokenstream::DelimSpan;
|
||||
use rustc_ast::{
|
||||
self as ast, AttrArgs, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, Safety,
|
||||
};
|
||||
use rustc_errors::{Applicability, Diagnostic, PResult};
|
||||
use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, template};
|
||||
use rustc_errors::{Applicability, FatalError, PResult};
|
||||
use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute};
|
||||
use rustc_hir::AttrPath;
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_parse::parse_in;
|
||||
use rustc_session::errors::report_lit_error;
|
||||
use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
|
||||
@@ -29,22 +30,15 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
|
||||
|
||||
// Check input tokens for built-in and key-value attributes.
|
||||
match builtin_attr_info {
|
||||
Some(BuiltinAttribute { name, .. }) => {
|
||||
// `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
|
||||
Some(BuiltinAttribute { name, template, .. }) => {
|
||||
if AttributeParser::<Late>::is_parsed_attribute(slice::from_ref(&name)) {
|
||||
return;
|
||||
}
|
||||
match parse_meta(psess, attr) {
|
||||
// Don't check safety again, we just did that
|
||||
Ok(meta) => {
|
||||
// FIXME The only unparsed builtin attributes that are left are the lint attributes, so we can hardcode the template here
|
||||
let lint_attrs = [sym::forbid, sym::allow, sym::warn, sym::deny, sym::expect];
|
||||
assert!(lint_attrs.contains(name));
|
||||
|
||||
let template = template!(
|
||||
List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#],
|
||||
"https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
|
||||
);
|
||||
check_builtin_meta_item(psess, &meta, attr.style, *name, template, false)
|
||||
check_builtin_meta_item(psess, &meta, attr.style, *name, *template, false)
|
||||
}
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
@@ -175,7 +169,7 @@ pub fn check_builtin_meta_item(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn emit_malformed_attribute(
|
||||
fn emit_malformed_attribute(
|
||||
psess: &ParseSess,
|
||||
style: ast::AttrStyle,
|
||||
span: Span,
|
||||
@@ -209,14 +203,14 @@ pub fn emit_malformed_attribute(
|
||||
suggestions.clear();
|
||||
}
|
||||
if should_warn(name) {
|
||||
let suggestions = suggestions.clone();
|
||||
psess.dyn_buffer_lint(
|
||||
psess.buffer_lint(
|
||||
ILL_FORMED_ATTRIBUTE_INPUT,
|
||||
span,
|
||||
ast::CRATE_NODE_ID,
|
||||
move |dcx, level| {
|
||||
crate::errors::IllFormedAttributeInput::new(&suggestions, template.docs, None)
|
||||
.into_diag(dcx, level)
|
||||
AttributeLintKind::IllFormedAttributeInput {
|
||||
suggestions: suggestions.clone(),
|
||||
docs: template.docs,
|
||||
help: None,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
@@ -237,3 +231,15 @@ pub fn emit_malformed_attribute(
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn emit_fatal_malformed_builtin_attribute(
|
||||
psess: &ParseSess,
|
||||
attr: &Attribute,
|
||||
name: Symbol,
|
||||
) -> ! {
|
||||
let template = BUILTIN_ATTRIBUTE_MAP.get(&name).expect("builtin attr defined").template;
|
||||
emit_malformed_attribute(psess, attr.style, attr.span, name, template);
|
||||
// This is fatal, otherwise it will likely cause a cascade of other errors
|
||||
// (and an error here is expected to be very rare).
|
||||
FatalError.raise()
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ use rustc_infer::traits::query::{
|
||||
};
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::{
|
||||
self, RePlaceholder, Region, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex, Unnormalized,
|
||||
self, RePlaceholder, Region, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex,
|
||||
};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
||||
@@ -275,7 +275,7 @@ where
|
||||
// the former fails to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs`
|
||||
// test. Check after #85499 lands to see if its fixes have erased this difference.
|
||||
let ty::ParamEnvAnd { param_env, value } = key;
|
||||
let _ = ocx.normalize(&cause, param_env, Unnormalized::new_wip(value.value));
|
||||
let _ = ocx.normalize(&cause, param_env, value.value);
|
||||
|
||||
let diag = try_extract_error_from_fulfill_cx(
|
||||
&ocx,
|
||||
@@ -322,7 +322,7 @@ where
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
|
||||
let ty::ParamEnvAnd { param_env, value } = key;
|
||||
let _ = ocx.deeply_normalize(&cause, param_env, Unnormalized::new_wip(value.value));
|
||||
let _ = ocx.deeply_normalize(&cause, param_env, value.value);
|
||||
|
||||
let diag = try_extract_error_from_fulfill_cx(
|
||||
&ocx,
|
||||
@@ -451,7 +451,7 @@ fn try_extract_error_from_region_constraints<'a, 'tcx>(
|
||||
(RePlaceholder(a_p), RePlaceholder(b_p)) => a_p.bound == b_p.bound,
|
||||
_ => a_region == b_region,
|
||||
};
|
||||
let mut check = |c: Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| match c.kind {
|
||||
let mut check = |c: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| match c.kind {
|
||||
ConstraintKind::RegSubReg
|
||||
if ((exact && c.sup == placeholder_region)
|
||||
|| (!exact && regions_the_same(c.sup, placeholder_region)))
|
||||
@@ -467,23 +467,13 @@ fn try_extract_error_from_region_constraints<'a, 'tcx>(
|
||||
{
|
||||
Some((c.sub, cause.clone()))
|
||||
}
|
||||
ConstraintKind::VarSubVar
|
||||
| ConstraintKind::RegSubVar
|
||||
| ConstraintKind::VarSubReg
|
||||
| ConstraintKind::RegSubReg => None,
|
||||
|
||||
ConstraintKind::VarEqVar | ConstraintKind::VarEqReg | ConstraintKind::RegEqReg => {
|
||||
unreachable!()
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let mut find_culprit = |exact_match: bool| {
|
||||
region_constraints
|
||||
.constraints
|
||||
.iter()
|
||||
.flat_map(|(constraint, cause)| {
|
||||
constraint.iter_outlives().map(move |constraint| (constraint, cause))
|
||||
})
|
||||
.find_map(|(constraint, cause)| check(constraint, cause, exact_match))
|
||||
};
|
||||
|
||||
|
||||
@@ -156,7 +156,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
.collect();
|
||||
generic_args.push((kw::SelfUpper, this.clone()));
|
||||
|
||||
let args = FormatArgs { this, generic_args, .. };
|
||||
let args = FormatArgs {
|
||||
this,
|
||||
// Unused
|
||||
this_sugared: String::new(),
|
||||
// Unused
|
||||
item_context: "",
|
||||
generic_args,
|
||||
};
|
||||
let CustomDiagnostic { message, label, notes, parent_label: _ } =
|
||||
directive.eval(None, &args);
|
||||
|
||||
@@ -747,19 +754,19 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
}
|
||||
|
||||
// Test the callee's predicates, substituting in `ref_ty` for the moved argument type.
|
||||
clauses.instantiate(tcx, new_args).predicates.iter().all(|clause| {
|
||||
clauses.instantiate(tcx, new_args).predicates.iter().all(|&(mut clause)| {
|
||||
// Normalize before testing to see through type aliases and projections.
|
||||
let normalized = tcx
|
||||
.try_normalize_erasing_regions(
|
||||
self.infcx.typing_env(self.infcx.param_env),
|
||||
*clause,
|
||||
)
|
||||
.unwrap_or_else(|_| clause.skip_norm_wip());
|
||||
if let Ok(normalized) = tcx.try_normalize_erasing_regions(
|
||||
self.infcx.typing_env(self.infcx.param_env),
|
||||
clause,
|
||||
) {
|
||||
clause = normalized;
|
||||
}
|
||||
self.infcx.predicate_must_hold_modulo_regions(&Obligation::new(
|
||||
tcx,
|
||||
ObligationCause::dummy(),
|
||||
self.infcx.param_env,
|
||||
normalized,
|
||||
clause,
|
||||
))
|
||||
})
|
||||
}) {
|
||||
@@ -4033,74 +4040,23 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
if let Some(decl) = local_decl
|
||||
&& decl.can_be_made_mutable()
|
||||
{
|
||||
let mut is_for_loop = false;
|
||||
let mut is_ref_pattern = false;
|
||||
if let LocalInfo::User(BindingForm::Var(VarBindingForm {
|
||||
opt_match_place: Some((_, match_span)),
|
||||
..
|
||||
})) = *decl.local_info()
|
||||
{
|
||||
if matches!(match_span.desugaring_kind(), Some(DesugaringKind::ForLoop)) {
|
||||
is_for_loop = true;
|
||||
|
||||
if let Some(body) = self.infcx.tcx.hir_maybe_body_owned_by(self.mir_def_id()) {
|
||||
struct RefPatternFinder<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
binding_span: Span,
|
||||
is_ref_pattern: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for RefPatternFinder<'tcx> {
|
||||
type NestedFilter = OnlyBodies;
|
||||
|
||||
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
|
||||
if !self.is_ref_pattern
|
||||
&& let hir::PatKind::Binding(_, _, ident, _) = pat.kind
|
||||
&& ident.span == self.binding_span
|
||||
{
|
||||
self.is_ref_pattern =
|
||||
self.tcx.hir_parent_iter(pat.hir_id).any(|(_, node)| {
|
||||
matches!(
|
||||
node,
|
||||
hir::Node::Pat(hir::Pat {
|
||||
kind: hir::PatKind::Ref(..),
|
||||
..
|
||||
})
|
||||
)
|
||||
});
|
||||
}
|
||||
hir::intravisit::walk_pat(self, pat);
|
||||
}
|
||||
}
|
||||
|
||||
let mut finder = RefPatternFinder {
|
||||
tcx: self.infcx.tcx,
|
||||
binding_span: decl.source_info.span,
|
||||
is_ref_pattern: false,
|
||||
};
|
||||
|
||||
finder.visit_body(body);
|
||||
is_ref_pattern = finder.is_ref_pattern;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let (span, message) = if is_for_loop
|
||||
&& is_ref_pattern
|
||||
let is_for_loop = matches!(
|
||||
decl.local_info(),
|
||||
LocalInfo::User(BindingForm::Var(VarBindingForm {
|
||||
opt_match_place: Some((_, match_span)),
|
||||
..
|
||||
})) if matches!(match_span.desugaring_kind(), Some(DesugaringKind::ForLoop))
|
||||
);
|
||||
let message = if is_for_loop
|
||||
&& let Ok(binding_name) =
|
||||
self.infcx.tcx.sess.source_map().span_to_snippet(decl.source_info.span)
|
||||
{
|
||||
(decl.source_info.span, format!("(mut {})", binding_name))
|
||||
format!("(mut {}) ", binding_name)
|
||||
} else {
|
||||
(decl.source_info.span.shrink_to_lo(), "mut ".to_string())
|
||||
"mut ".to_string()
|
||||
};
|
||||
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
decl.source_info.span.shrink_to_lo(),
|
||||
"consider making this binding mutable",
|
||||
message,
|
||||
Applicability::MachineApplicable,
|
||||
@@ -4215,20 +4171,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
if is_closure {
|
||||
None
|
||||
} else {
|
||||
let ty = self
|
||||
.infcx
|
||||
.tcx
|
||||
.type_of(self.mir_def_id())
|
||||
.instantiate_identity()
|
||||
.skip_norm_wip();
|
||||
let ty = self.infcx.tcx.type_of(self.mir_def_id()).instantiate_identity();
|
||||
match ty.kind() {
|
||||
ty::FnDef(_, _) | ty::FnPtr(..) => self.annotate_fn_sig(
|
||||
self.mir_def_id(),
|
||||
self.infcx
|
||||
.tcx
|
||||
.fn_sig(self.mir_def_id())
|
||||
.instantiate_identity()
|
||||
.skip_norm_wip(),
|
||||
self.infcx.tcx.fn_sig(self.mir_def_id()).instantiate_identity(),
|
||||
),
|
||||
_ => None,
|
||||
}
|
||||
|
||||
@@ -602,14 +602,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
BorrowedContentSource::DerefRawPointer
|
||||
} else if base_ty.is_mutable_ptr() {
|
||||
BorrowedContentSource::DerefMutableRef
|
||||
} else if base_ty.is_ref() {
|
||||
BorrowedContentSource::DerefSharedRef
|
||||
} else {
|
||||
// Custom type implementing `Deref` (e.g. `MyBox<T>`, `Rc<T>`, `Arc<T>`)
|
||||
// that wasn't detected via the MIR init trace above. This can happen
|
||||
// when the deref base is initialized by a regular statement rather than
|
||||
// a `TerminatorKind::Call` with `CallSource::OverloadedOperator`.
|
||||
BorrowedContentSource::OverloadedDeref(base_ty)
|
||||
BorrowedContentSource::DerefSharedRef
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1008,14 +1002,6 @@ struct CapturedMessageOpt {
|
||||
maybe_reinitialized_locations_is_empty: bool,
|
||||
}
|
||||
|
||||
/// Tracks whether [`MirBorrowckCtxt::explain_captures`] emitted a clone
|
||||
/// suggestion, so callers can avoid emitting redundant suggestions downstream.
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub(super) enum CloneSuggestion {
|
||||
Emitted,
|
||||
NotEmitted,
|
||||
}
|
||||
|
||||
impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
/// Finds the spans associated to a move or copy of move_place at location.
|
||||
pub(super) fn move_spans(
|
||||
@@ -1240,7 +1226,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
move_spans: UseSpans<'tcx>,
|
||||
moved_place: Place<'tcx>,
|
||||
msg_opt: CapturedMessageOpt,
|
||||
) -> CloneSuggestion {
|
||||
) {
|
||||
let CapturedMessageOpt {
|
||||
is_partial_move: is_partial,
|
||||
is_loop_message,
|
||||
@@ -1249,7 +1235,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
has_suggest_reborrow,
|
||||
maybe_reinitialized_locations_is_empty,
|
||||
} = msg_opt;
|
||||
let mut suggested_cloning = false;
|
||||
if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
|
||||
let place_name = self
|
||||
.describe_place(moved_place.as_ref())
|
||||
@@ -1381,12 +1366,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
let parent_self_ty =
|
||||
matches!(tcx.def_kind(parent_did), rustc_hir::def::DefKind::Impl { .. })
|
||||
.then_some(parent_did)
|
||||
.and_then(|did| {
|
||||
match tcx.type_of(did).instantiate_identity().skip_norm_wip().kind()
|
||||
{
|
||||
ty::Adt(def, ..) => Some(def.did()),
|
||||
_ => None,
|
||||
}
|
||||
.and_then(|did| match tcx.type_of(did).instantiate_identity().kind() {
|
||||
ty::Adt(def, ..) => Some(def.did()),
|
||||
_ => None,
|
||||
});
|
||||
let is_option_or_result = parent_self_ty.is_some_and(|def_id| {
|
||||
matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
|
||||
@@ -1463,10 +1445,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
&& let self_ty = self.infcx.instantiate_binder_with_fresh_vars(
|
||||
fn_call_span,
|
||||
BoundRegionConversionTime::FnCall,
|
||||
tcx.fn_sig(method_did)
|
||||
.instantiate(tcx, method_args)
|
||||
.skip_norm_wip()
|
||||
.input(0),
|
||||
tcx.fn_sig(method_did).instantiate(tcx, method_args).input(0),
|
||||
)
|
||||
&& self.infcx.can_eq(self.infcx.param_env, ty, self_ty)
|
||||
{
|
||||
@@ -1476,26 +1455,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
has_sugg = true;
|
||||
}
|
||||
if let Some(clone_trait) = tcx.lang_items().clone_trait() {
|
||||
// Check whether the deref is from a custom Deref impl
|
||||
// (e.g. Rc, Box) or a built-in reference deref.
|
||||
// For built-in derefs with Clone fully satisfied, we skip
|
||||
// the UFCS suggestion here and let `suggest_cloning`
|
||||
// downstream emit a simpler `.clone()` suggestion instead.
|
||||
let has_overloaded_deref =
|
||||
moved_place.iter_projections().any(|(place, elem)| {
|
||||
matches!(elem, ProjectionElem::Deref)
|
||||
&& matches!(
|
||||
self.borrowed_content_source(place),
|
||||
BorrowedContentSource::OverloadedDeref(_)
|
||||
| BorrowedContentSource::OverloadedIndex(_)
|
||||
)
|
||||
});
|
||||
|
||||
let has_deref = moved_place
|
||||
let sugg = if moved_place
|
||||
.iter_projections()
|
||||
.any(|(_, elem)| matches!(elem, ProjectionElem::Deref));
|
||||
|
||||
let sugg = if has_deref {
|
||||
.any(|(_, elem)| matches!(elem, ProjectionElem::Deref))
|
||||
{
|
||||
let (start, end) = if let Some(expr) = self.find_expr(move_span)
|
||||
&& let Some(_) = self.clone_on_reference(expr)
|
||||
&& let hir::ExprKind::MethodCall(_, rcvr, _, _) = expr.kind
|
||||
@@ -1521,58 +1484,43 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
self.infcx.param_env,
|
||||
) && !has_sugg
|
||||
{
|
||||
let skip_for_simple_clone =
|
||||
has_deref && !has_overloaded_deref && errors.is_empty();
|
||||
if !skip_for_simple_clone {
|
||||
let msg = match &errors[..] {
|
||||
[] => "you can `clone` the value and consume it, but \
|
||||
this might not be your desired behavior"
|
||||
.to_string(),
|
||||
[error] => {
|
||||
format!(
|
||||
"you could `clone` the value and consume it, if \
|
||||
the `{}` trait bound could be satisfied",
|
||||
error.obligation.predicate,
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
format!(
|
||||
"you could `clone` the value and consume it, if \
|
||||
the following trait bounds could be satisfied: \
|
||||
{}",
|
||||
listify(
|
||||
&errors,
|
||||
|e: &FulfillmentError<'tcx>| format!(
|
||||
"`{}`",
|
||||
e.obligation.predicate
|
||||
)
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
};
|
||||
err.multipart_suggestion(
|
||||
msg,
|
||||
sugg,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
||||
suggested_cloning = errors.is_empty();
|
||||
|
||||
for error in errors {
|
||||
if let FulfillmentErrorCode::Select(
|
||||
SelectionError::Unimplemented,
|
||||
) = error.code
|
||||
&& let ty::PredicateKind::Clause(ty::ClauseKind::Trait(
|
||||
pred,
|
||||
)) = error.obligation.predicate.kind().skip_binder()
|
||||
{
|
||||
self.infcx.err_ctxt().suggest_derive(
|
||||
&error.obligation,
|
||||
err,
|
||||
error.obligation.predicate.kind().rebind(pred),
|
||||
);
|
||||
}
|
||||
let msg = match &errors[..] {
|
||||
[] => "you can `clone` the value and consume it, but this \
|
||||
might not be your desired behavior"
|
||||
.to_string(),
|
||||
[error] => {
|
||||
format!(
|
||||
"you could `clone` the value and consume it, if the \
|
||||
`{}` trait bound could be satisfied",
|
||||
error.obligation.predicate,
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
format!(
|
||||
"you could `clone` the value and consume it, if the \
|
||||
following trait bounds could be satisfied: {}",
|
||||
listify(&errors, |e: &FulfillmentError<'tcx>| format!(
|
||||
"`{}`",
|
||||
e.obligation.predicate
|
||||
))
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
};
|
||||
err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect);
|
||||
for error in errors {
|
||||
if let FulfillmentErrorCode::Select(
|
||||
SelectionError::Unimplemented,
|
||||
) = error.code
|
||||
&& let ty::PredicateKind::Clause(ty::ClauseKind::Trait(
|
||||
pred,
|
||||
)) = error.obligation.predicate.kind().skip_binder()
|
||||
{
|
||||
self.infcx.err_ctxt().suggest_derive(
|
||||
&error.obligation,
|
||||
err,
|
||||
error.obligation.predicate.kind().rebind(pred),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1604,7 +1552,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
})
|
||||
}
|
||||
}
|
||||
if suggested_cloning { CloneSuggestion::Emitted } else { CloneSuggestion::NotEmitted }
|
||||
}
|
||||
|
||||
/// Skip over locals that begin with an underscore or have no name
|
||||
|
||||
@@ -14,9 +14,7 @@ use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::MirBorrowckCtxt;
|
||||
use crate::diagnostics::{
|
||||
BorrowedContentSource, CapturedMessageOpt, CloneSuggestion, DescribePlaceOpt, UseSpans,
|
||||
};
|
||||
use crate::diagnostics::{CapturedMessageOpt, DescribePlaceOpt, UseSpans};
|
||||
use crate::prefixes::PrefixSet;
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -271,19 +269,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
.span_delayed_bug(span, "Type may implement copy, but there is no other error.");
|
||||
return;
|
||||
}
|
||||
|
||||
let mut has_clone_suggestion = CloneSuggestion::NotEmitted;
|
||||
let mut err = match kind {
|
||||
&IllegalMoveOriginKind::BorrowedContent { target_place } => {
|
||||
let (diag, clone_sugg) = self.report_cannot_move_from_borrowed_content(
|
||||
&IllegalMoveOriginKind::BorrowedContent { target_place } => self
|
||||
.report_cannot_move_from_borrowed_content(
|
||||
original_path,
|
||||
target_place,
|
||||
span,
|
||||
use_spans,
|
||||
);
|
||||
has_clone_suggestion = clone_sugg;
|
||||
diag
|
||||
}
|
||||
),
|
||||
&IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
|
||||
self.cannot_move_out_of_interior_of_drop(span, ty)
|
||||
}
|
||||
@@ -292,7 +285,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
}
|
||||
};
|
||||
|
||||
self.add_move_hints(error, &mut err, span, has_clone_suggestion);
|
||||
self.add_move_hints(error, &mut err, span);
|
||||
self.buffer_error(err);
|
||||
}
|
||||
|
||||
@@ -433,7 +426,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
deref_target_place: Place<'tcx>,
|
||||
span: Span,
|
||||
use_spans: Option<UseSpans<'tcx>>,
|
||||
) -> (Diag<'infcx>, CloneSuggestion) {
|
||||
) -> Diag<'infcx> {
|
||||
let tcx = self.infcx.tcx;
|
||||
// Inspect the type of the content behind the
|
||||
// borrow to provide feedback about why this
|
||||
@@ -454,8 +447,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
let decl = &self.body.local_decls[local];
|
||||
let local_name = self.local_name(local).map(|sym| format!("`{sym}`"));
|
||||
if decl.is_ref_for_guard() {
|
||||
return (
|
||||
self.cannot_move_out_of(
|
||||
return self
|
||||
.cannot_move_out_of(
|
||||
span,
|
||||
&format!(
|
||||
"{} in pattern guard",
|
||||
@@ -465,14 +458,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
.with_note(
|
||||
"variables bound in patterns cannot be moved from \
|
||||
until after the end of the pattern guard",
|
||||
),
|
||||
CloneSuggestion::NotEmitted,
|
||||
);
|
||||
);
|
||||
} else if decl.is_ref_to_static() {
|
||||
return (
|
||||
self.report_cannot_move_from_static(move_place, span),
|
||||
CloneSuggestion::NotEmitted,
|
||||
);
|
||||
return self.report_cannot_move_from_static(move_place, span);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -551,12 +539,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
has_suggest_reborrow: false,
|
||||
maybe_reinitialized_locations_is_empty: true,
|
||||
};
|
||||
let suggested_cloning = if let Some(use_spans) = use_spans {
|
||||
self.explain_captures(&mut err, span, span, use_spans, move_place, msg_opt)
|
||||
} else {
|
||||
CloneSuggestion::NotEmitted
|
||||
};
|
||||
(err, suggested_cloning)
|
||||
if let Some(use_spans) = use_spans {
|
||||
self.explain_captures(&mut err, span, span, use_spans, move_place, msg_opt);
|
||||
}
|
||||
err
|
||||
}
|
||||
|
||||
fn report_closure_move_error(
|
||||
@@ -654,9 +640,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
// 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()) {
|
||||
let pred = pred.skip_norm_wip();
|
||||
let dominated_by_fn_trait = self
|
||||
.closure_clause_kind(pred, def_id, asyncness)
|
||||
.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
|
||||
@@ -690,52 +675,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Suggest cloning via UFCS when a move occurs through a custom `Deref` impl.
|
||||
///
|
||||
/// A simple `.clone()` on a type like `MyBox<Vec<i32>>` would clone the wrapper,
|
||||
/// not the inner `Vec<i32>`. Instead, we suggest `<Vec<i32> as Clone>::clone(&val)`.
|
||||
fn suggest_cloning_through_overloaded_deref(
|
||||
&self,
|
||||
err: &mut Diag<'_>,
|
||||
ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
) -> CloneSuggestion {
|
||||
let tcx = self.infcx.tcx;
|
||||
let Some(clone_trait) = tcx.lang_items().clone_trait() else {
|
||||
return CloneSuggestion::NotEmitted;
|
||||
};
|
||||
let Some(errors) =
|
||||
self.infcx.type_implements_trait_shallow(clone_trait, ty, self.infcx.param_env)
|
||||
else {
|
||||
return CloneSuggestion::NotEmitted;
|
||||
};
|
||||
|
||||
if !errors.is_empty() {
|
||||
return CloneSuggestion::NotEmitted;
|
||||
}
|
||||
let sugg = vec![
|
||||
(span.shrink_to_lo(), format!("<{ty} as Clone>::clone(&")),
|
||||
(span.shrink_to_hi(), ")".to_string()),
|
||||
];
|
||||
err.multipart_suggestion(
|
||||
"you can `clone` the value and consume it, but this might not be \
|
||||
your desired behavior",
|
||||
sugg,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
CloneSuggestion::Emitted
|
||||
}
|
||||
|
||||
fn add_move_hints(
|
||||
&self,
|
||||
error: GroupedMoveError<'tcx>,
|
||||
err: &mut Diag<'_>,
|
||||
span: Span,
|
||||
has_clone_suggestion: CloneSuggestion,
|
||||
) {
|
||||
fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span: Span) {
|
||||
match error {
|
||||
GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => {
|
||||
self.add_borrow_suggestions(err, span, !binds_to.is_empty());
|
||||
self.add_borrow_suggestions(err, span);
|
||||
if binds_to.is_empty() {
|
||||
let place_ty = move_from.ty(self.body, self.infcx.tcx).ty;
|
||||
let place_desc = match self.describe_place(move_from.as_ref()) {
|
||||
@@ -775,43 +718,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
None => "value".to_string(),
|
||||
};
|
||||
|
||||
if has_clone_suggestion == CloneSuggestion::NotEmitted {
|
||||
// Check if the move is directly through a custom Deref impl
|
||||
// (e.g. `*my_box` where MyBox implements Deref).
|
||||
// A simple `.clone()` would clone the wrapper type rather than
|
||||
// the inner value, so we need a UFCS suggestion instead.
|
||||
//
|
||||
// However, if there are further projections after the deref
|
||||
// (e.g. `(*rc).field`), the value accessed is already the inner
|
||||
// type and a simple `.clone()` works correctly.
|
||||
let needs_ufcs = original_path.projection.last()
|
||||
== Some(&ProjectionElem::Deref)
|
||||
&& original_path.iter_projections().any(|(place, elem)| {
|
||||
matches!(elem, ProjectionElem::Deref)
|
||||
&& matches!(
|
||||
self.borrowed_content_source(place),
|
||||
BorrowedContentSource::OverloadedDeref(_)
|
||||
| BorrowedContentSource::OverloadedIndex(_)
|
||||
)
|
||||
});
|
||||
|
||||
let emitted_ufcs = if needs_ufcs {
|
||||
self.suggest_cloning_through_overloaded_deref(err, place_ty, use_span)
|
||||
} else {
|
||||
CloneSuggestion::NotEmitted
|
||||
};
|
||||
|
||||
if emitted_ufcs == CloneSuggestion::NotEmitted {
|
||||
if let Some(expr) = self.find_expr(use_span) {
|
||||
self.suggest_cloning(
|
||||
err,
|
||||
original_path.as_ref(),
|
||||
place_ty,
|
||||
expr,
|
||||
Some(use_spans),
|
||||
);
|
||||
}
|
||||
}
|
||||
if let Some(expr) = self.find_expr(use_span) {
|
||||
self.suggest_cloning(
|
||||
err,
|
||||
original_path.as_ref(),
|
||||
place_ty,
|
||||
expr,
|
||||
Some(use_spans),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(upvar_field) = self
|
||||
@@ -873,67 +787,29 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn add_borrow_suggestions(
|
||||
&self,
|
||||
err: &mut Diag<'_>,
|
||||
span: Span,
|
||||
is_destructuring_pattern_move: bool,
|
||||
) {
|
||||
fn add_borrow_suggestions(&self, err: &mut Diag<'_>, span: Span) {
|
||||
match self.infcx.tcx.sess.source_map().span_to_snippet(span) {
|
||||
Ok(snippet) if snippet.starts_with('*') => {
|
||||
let sp = span.with_lo(span.lo() + BytePos(1));
|
||||
let inner = self.find_expr(sp);
|
||||
let mut is_raw_ptr = false;
|
||||
let mut is_ref = false;
|
||||
let mut is_destructuring_assignment = false;
|
||||
let mut is_nested_deref = false;
|
||||
if let Some(inner) = inner {
|
||||
is_nested_deref =
|
||||
matches!(inner.kind, hir::ExprKind::Unary(hir::UnOp::Deref, _));
|
||||
let typck_result = self.infcx.tcx.typeck(self.mir_def_id());
|
||||
if let Some(inner_type) = typck_result.node_type_opt(inner.hir_id) {
|
||||
if matches!(inner_type.kind(), ty::RawPtr(..)) {
|
||||
is_raw_ptr = true;
|
||||
} else if matches!(inner_type.kind(), ty::Ref(..)) {
|
||||
is_ref = true;
|
||||
}
|
||||
}
|
||||
is_destructuring_assignment =
|
||||
self.infcx.tcx.hir_parent_iter(inner.hir_id).any(|(_, node)| {
|
||||
matches!(
|
||||
node,
|
||||
hir::Node::LetStmt(&hir::LetStmt {
|
||||
source: hir::LocalSource::AssignDesugar,
|
||||
..
|
||||
})
|
||||
)
|
||||
});
|
||||
}
|
||||
// If the `inner` is a raw pointer, do not suggest removing the "*", see #126863
|
||||
// FIXME: need to check whether the assigned object can be a raw pointer, see `tests/ui/borrowck/issue-20801.rs`.
|
||||
if is_raw_ptr {
|
||||
return;
|
||||
}
|
||||
|
||||
if !is_destructuring_pattern_move || is_ref {
|
||||
if !is_raw_ptr {
|
||||
err.span_suggestion_verbose(
|
||||
span.with_hi(span.lo() + BytePos(1)),
|
||||
"consider removing the dereference here",
|
||||
String::new(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else if !is_destructuring_assignment && !is_nested_deref {
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_lo(),
|
||||
"consider borrowing here",
|
||||
'&',
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
err.span_help(
|
||||
span,
|
||||
"destructuring assignment cannot borrow from this expression; consider using a `let` binding instead",
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
|
||||
@@ -493,7 +493,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
for (_, node) in self.infcx.tcx.hir_parent_iter(upvar_hir_id) {
|
||||
if let Some(fn_decl) = node.fn_decl() {
|
||||
if !matches!(
|
||||
fn_decl.implicit_self(),
|
||||
fn_decl.implicit_self,
|
||||
hir::ImplicitSelfKind::RefImm | hir::ImplicitSelfKind::RefMut
|
||||
) {
|
||||
err.span_suggestion_verbose(
|
||||
@@ -810,7 +810,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
&& let Some(ty) = sig.decl.inputs.get(local.index() - 1)
|
||||
&& let hir::TyKind::Ref(_, mut_ty) = ty.kind
|
||||
&& let hir::Mutability::Not = mut_ty.mutbl
|
||||
&& sig.decl.implicit_self().has_implicit_self()
|
||||
&& sig.decl.implicit_self.has_implicit_self()
|
||||
{
|
||||
Some(ty.span)
|
||||
} else {
|
||||
@@ -1147,7 +1147,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
arg_pos
|
||||
.and_then(|pos| {
|
||||
sig.decl.inputs.get(
|
||||
pos + if sig.decl.implicit_self().has_implicit_self() {
|
||||
pos + if sig.decl.implicit_self.has_implicit_self() {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
@@ -1410,20 +1410,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
(span, " mut".to_owned(), true)
|
||||
// If there is already a binding, we modify it to be `mut`.
|
||||
} else if binding_exists {
|
||||
// Replace the sigil with the mutable version. We may be dealing
|
||||
// with parser recovery here and cannot assume the user actually
|
||||
// typed `&` or `*const`, so we compute the prefix from the snippet.
|
||||
let Ok(src) = self.infcx.tcx.sess.source_map().span_to_snippet(span) else {
|
||||
return;
|
||||
};
|
||||
let (prefix_len, replacement) = if local_decl.ty.is_ref() {
|
||||
(src.chars().next().map_or(0, char::len_utf8), "&mut ")
|
||||
} else {
|
||||
(src.find("const").map_or(1, |i| i + "const".len()), "*mut ")
|
||||
};
|
||||
let ws_len = src[prefix_len..].len() - src[prefix_len..].trim_start().len();
|
||||
let span = span.with_hi(span.lo() + BytePos((prefix_len + ws_len) as u32));
|
||||
(span, replacement.to_owned(), true)
|
||||
// Shrink the span to just after the `&` in `&variable`.
|
||||
let span = span.with_lo(span.lo() + BytePos(1)).shrink_to_lo();
|
||||
(span, "mut ".to_owned(), true)
|
||||
} else {
|
||||
// Otherwise, suggest that the user annotates the binding; We provide the
|
||||
// type of the local.
|
||||
|
||||
@@ -9,7 +9,6 @@ use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::mir::{self, ConstraintCategory, Location};
|
||||
use rustc_middle::ty::{
|
||||
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
|
||||
Unnormalized,
|
||||
};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::error_reporting::infer::region::unexpected_hidden_region_diagnostic;
|
||||
@@ -220,12 +219,12 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for FindOpaqueRegion<'_, 'tcx> {
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
|
||||
// If we find an opaque in a local ty, then for each of its captured regions,
|
||||
// try to find a path between that captured regions and our borrow region...
|
||||
if let ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) = *ty.kind()
|
||||
if let ty::Alias(opaque @ ty::AliasTy { kind: ty::Opaque { def_id }, .. }) = *ty.kind()
|
||||
&& let hir::OpaqueTyOrigin::FnReturn { parent, in_trait_or_impl: None } =
|
||||
self.tcx.opaque_ty_origin(def_id)
|
||||
{
|
||||
let variances = self.tcx.variances_of(def_id);
|
||||
for (idx, (arg, variance)) in std::iter::zip(args, variances).enumerate() {
|
||||
for (idx, (arg, variance)) in std::iter::zip(opaque.args, variances).enumerate() {
|
||||
// Skip uncaptured args.
|
||||
if *variance == ty::Bivariant {
|
||||
continue;
|
||||
@@ -277,13 +276,12 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for CheckExplicitRegionMentionAndCollectGen
|
||||
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
|
||||
match *ty.kind() {
|
||||
ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) => {
|
||||
ty::Alias(opaque @ ty::AliasTy { kind: ty::Opaque { def_id }, .. }) => {
|
||||
if self.seen_opaques.insert(def_id) {
|
||||
for (bound, _) in self
|
||||
.tcx
|
||||
.explicit_item_bounds(def_id)
|
||||
.iter_instantiated_copied(self.tcx, args)
|
||||
.map(Unnormalized::skip_norm_wip)
|
||||
.iter_instantiated_copied(self.tcx, opaque.args)
|
||||
{
|
||||
bound.visit_with(self)?;
|
||||
}
|
||||
|
||||
@@ -15,8 +15,7 @@ use rustc_middle::bug;
|
||||
use rustc_middle::hir::place::PlaceBase;
|
||||
use rustc_middle::mir::{AnnotationSource, ConstraintCategory, ReturnConstraint};
|
||||
use rustc_middle::ty::{
|
||||
self, FnSigKind, GenericArgs, Region, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitor,
|
||||
fold_regions,
|
||||
self, GenericArgs, Region, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitor, fold_regions,
|
||||
};
|
||||
use rustc_span::{Ident, Span, kw};
|
||||
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
||||
@@ -596,7 +595,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
|
||||
let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty;
|
||||
if let ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, .. }) = *output_ty.kind() {
|
||||
output_ty = self.infcx.tcx.type_of(def_id).instantiate_identity().skip_norm_wip()
|
||||
output_ty = self.infcx.tcx.type_of(def_id).instantiate_identity()
|
||||
};
|
||||
|
||||
debug!("report_fnmut_error: output_ty={:?}", output_ty);
|
||||
@@ -687,8 +686,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
|| (*category == ConstraintCategory::Assignment
|
||||
&& self.regioncx.universal_regions().defining_ty.is_fn_def())
|
||||
|| self.regioncx.universal_regions().defining_ty.is_const()
|
||||
|| (fr_name_and_span.is_none()
|
||||
&& self.regioncx.universal_regions().defining_ty.is_fn_def())
|
||||
{
|
||||
return self.report_general_error(errci);
|
||||
}
|
||||
@@ -933,7 +930,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
debug!(?fn_did, ?args);
|
||||
|
||||
// Only suggest this on function calls, not closures
|
||||
let ty = tcx.type_of(fn_did).instantiate_identity().skip_norm_wip();
|
||||
let ty = tcx.type_of(fn_did).instantiate_identity();
|
||||
debug!("ty: {:?}, ty.kind: {:?}", ty, ty.kind());
|
||||
if let ty::Closure(_, _) = ty.kind() {
|
||||
return;
|
||||
@@ -1053,8 +1050,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let ty::Closure(_, args) =
|
||||
*tcx.type_of(closure_def_id).instantiate_identity().skip_norm_wip().kind()
|
||||
let ty::Closure(_, args) = *tcx.type_of(closure_def_id).instantiate_identity().kind()
|
||||
else {
|
||||
return;
|
||||
};
|
||||
@@ -1085,14 +1081,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
}
|
||||
|
||||
// Build a new closure where the return type is an owned value, instead of a ref.
|
||||
let fn_sig_kind =
|
||||
FnSigKind::default().set_safe(true).set_c_variadic(liberated_sig.c_variadic());
|
||||
let closure_sig_as_fn_ptr_ty = Ty::new_fn_ptr(
|
||||
tcx,
|
||||
ty::Binder::dummy(tcx.mk_fn_sig(
|
||||
liberated_sig.inputs().iter().copied(),
|
||||
peeled_ty,
|
||||
fn_sig_kind,
|
||||
liberated_sig.c_variadic,
|
||||
hir::Safety::Safe,
|
||||
rustc_abi::ExternAbi::Rust,
|
||||
)),
|
||||
);
|
||||
let closure_ty = Ty::new_closure(
|
||||
@@ -1152,13 +1148,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
let ocx = ObligationCtxt::new(&self.infcx);
|
||||
ocx.register_obligations(preds.iter().map(|(pred, span)| {
|
||||
trace!(?pred);
|
||||
Obligation::misc(
|
||||
tcx,
|
||||
span,
|
||||
self.mir_def_id(),
|
||||
self.infcx.param_env,
|
||||
pred.skip_norm_wip(),
|
||||
)
|
||||
Obligation::misc(tcx, span, self.mir_def_id(), self.infcx.param_env, pred)
|
||||
}));
|
||||
|
||||
if ocx.evaluate_obligations_error_on_ambiguity().is_empty() && count > 0 {
|
||||
|
||||
@@ -6,7 +6,7 @@ use rustc_errors::{Diag, EmissionGuarantee};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_middle::ty::print::RegionHighlightMode;
|
||||
use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, RegionVid, Ty, Unnormalized};
|
||||
use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, RegionVid, Ty};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::{DUMMY_SP, Span, Symbol, kw, sym};
|
||||
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
||||
@@ -418,7 +418,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
|
||||
|
||||
// Get the parent fn's signature with liberated late-bound regions,
|
||||
// so we have `ReLateParam` instead of `ReBound`.
|
||||
let parent_fn_sig = tcx.fn_sig(parent_def_id).instantiate_identity().skip_norm_wip();
|
||||
let parent_fn_sig = tcx.fn_sig(parent_def_id).instantiate_identity();
|
||||
let liberated_sig = tcx.liberate_late_bound_regions(parent_def_id, parent_fn_sig);
|
||||
let parent_param_ty = *liberated_sig.inputs().get(param_index)?;
|
||||
|
||||
@@ -499,18 +499,18 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
|
||||
fr: RegionVid,
|
||||
) -> Option<RegionName> {
|
||||
let implicit_inputs = self.regioncx.universal_regions().defining_ty.implicit_inputs();
|
||||
let user_arg_index = self.regioncx.get_user_arg_index_for_region(self.infcx.tcx, fr)?;
|
||||
let argument_index = self.regioncx.get_argument_index_for_region(self.infcx.tcx, fr)?;
|
||||
|
||||
let arg_ty = self.regioncx.universal_regions().unnormalized_input_tys
|
||||
[implicit_inputs + user_arg_index];
|
||||
[implicit_inputs + argument_index];
|
||||
let (_, span) = self.regioncx.get_argument_name_and_span_for_region(
|
||||
self.body,
|
||||
self.local_names(),
|
||||
user_arg_index,
|
||||
argument_index,
|
||||
);
|
||||
|
||||
let highlight = self
|
||||
.get_argument_hir_ty_for_highlighting(user_arg_index)
|
||||
.get_argument_hir_ty_for_highlighting(argument_index)
|
||||
.and_then(|arg_hir_ty| self.highlight_if_we_can_match_hir_ty(fr, arg_ty, arg_hir_ty))
|
||||
.unwrap_or_else(|| {
|
||||
// `highlight_if_we_cannot_match_hir_ty` needs to know the number we will give to
|
||||
@@ -528,11 +528,10 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
|
||||
|
||||
fn get_argument_hir_ty_for_highlighting(
|
||||
&self,
|
||||
user_arg_index: usize,
|
||||
argument_index: usize,
|
||||
) -> Option<&hir::Ty<'tcx>> {
|
||||
let fn_decl = self.infcx.tcx.hir_fn_decl_by_hir_id(self.mir_hir_id())?;
|
||||
// Closures don't have implicit self arguments in HIR, so use `user_arg_index` directly.
|
||||
let argument_hir_ty: &hir::Ty<'_> = fn_decl.inputs.get(user_arg_index)?;
|
||||
let argument_hir_ty: &hir::Ty<'_> = fn_decl.inputs.get(argument_index)?;
|
||||
match argument_hir_ty.kind {
|
||||
// This indicates a variable with no type annotation, like
|
||||
// `|x|`... in that case, we can't highlight the type but
|
||||
@@ -1024,10 +1023,10 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
|
||||
return None;
|
||||
};
|
||||
|
||||
let found = tcx.any_free_region_meets(
|
||||
&tcx.type_of(region_parent).instantiate_identity().skip_norm_wip(),
|
||||
|r| r.kind() == ty::ReEarlyParam(region),
|
||||
);
|
||||
let found = tcx
|
||||
.any_free_region_meets(&tcx.type_of(region_parent).instantiate_identity(), |r| {
|
||||
r.kind() == ty::ReEarlyParam(region)
|
||||
});
|
||||
|
||||
Some(RegionName {
|
||||
name: self.synthesize_region_name(),
|
||||
@@ -1052,15 +1051,12 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
|
||||
return None;
|
||||
};
|
||||
|
||||
let predicates: Vec<_> = self
|
||||
let predicates = self
|
||||
.infcx
|
||||
.tcx
|
||||
.predicates_of(self.body.source.def_id())
|
||||
.instantiate_identity(self.infcx.tcx)
|
||||
.predicates
|
||||
.into_iter()
|
||||
.map(Unnormalized::skip_norm_wip)
|
||||
.collect();
|
||||
.predicates;
|
||||
|
||||
if let Some(upvar_index) = self
|
||||
.regioncx
|
||||
|
||||
@@ -31,7 +31,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
})
|
||||
.or_else(|| {
|
||||
debug!("get_var_name_and_span_for_region: attempting argument");
|
||||
self.get_user_arg_index_for_region(tcx, fr).and_then(|index| {
|
||||
self.get_argument_index_for_region(tcx, fr).and_then(|index| {
|
||||
let local = self.user_arg_index_to_local(body, index);
|
||||
if body_uses_local(body, local) {
|
||||
Some(self.get_argument_name_and_span_for_region(body, local_names, index))
|
||||
@@ -93,26 +93,26 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
///
|
||||
/// N.B., in the case of a closure, the index is indexing into the signature as seen by the
|
||||
/// user - in particular, index 0 is not the implicit self parameter.
|
||||
pub(crate) fn get_user_arg_index_for_region(
|
||||
pub(crate) fn get_argument_index_for_region(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
fr: RegionVid,
|
||||
) -> Option<usize> {
|
||||
let implicit_inputs = self.universal_regions().defining_ty.implicit_inputs();
|
||||
let user_arg_index =
|
||||
let argument_index =
|
||||
self.universal_regions().unnormalized_input_tys.iter().skip(implicit_inputs).position(
|
||||
|arg_ty| {
|
||||
debug!("get_user_arg_index_for_region: arg_ty = {arg_ty:?}");
|
||||
debug!("get_argument_index_for_region: arg_ty = {arg_ty:?}");
|
||||
tcx.any_free_region_meets(arg_ty, |r| r.as_var() == fr)
|
||||
},
|
||||
)?;
|
||||
|
||||
debug!(
|
||||
"get_user_arg_index_for_region: found {fr:?} in argument {user_arg_index} which has type {:?}",
|
||||
self.universal_regions().unnormalized_input_tys[user_arg_index],
|
||||
"get_argument_index_for_region: found {fr:?} in argument {argument_index} which has type {:?}",
|
||||
self.universal_regions().unnormalized_input_tys[argument_index],
|
||||
);
|
||||
|
||||
Some(user_arg_index)
|
||||
Some(argument_index)
|
||||
}
|
||||
|
||||
/// Given the index of an argument as seen from the user (i.e. excluding
|
||||
@@ -128,9 +128,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
&self,
|
||||
body: &Body<'tcx>,
|
||||
local_names: &IndexSlice<Local, Option<Symbol>>,
|
||||
user_arg_index: usize,
|
||||
argument_index: usize,
|
||||
) -> (Option<Symbol>, Span) {
|
||||
let argument_local = self.user_arg_index_to_local(body, user_arg_index);
|
||||
let argument_local = self.user_arg_index_to_local(body, argument_index);
|
||||
debug!("get_argument_name_and_span_for_region: argument_local={argument_local:?}");
|
||||
|
||||
let argument_name = local_names[argument_local];
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![cfg_attr(bootstrap, feature(assert_matches))]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(default_field_values)]
|
||||
#![feature(file_buffered)]
|
||||
|
||||
@@ -107,7 +107,7 @@ impl LocalizedConstraintGraphVisitor for LocalizedOutlivesConstraintCollector {
|
||||
/// - a mermaid graph of the NLL regions and the constraints between them
|
||||
/// - a mermaid graph of the NLL SCCs and the constraints between them
|
||||
fn emit_polonius_dump<'tcx>(
|
||||
dumper: &MirDumper<'_, 'tcx>,
|
||||
dumper: &MirDumper<'_, '_, 'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
@@ -186,7 +186,7 @@ fn emit_polonius_dump<'tcx>(
|
||||
|
||||
/// Emits the polonius MIR, as escaped HTML.
|
||||
fn emit_html_mir<'tcx>(
|
||||
dumper: &MirDumper<'_, 'tcx>,
|
||||
dumper: &MirDumper<'_, '_, 'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
out: &mut dyn io::Write,
|
||||
) -> io::Result<()> {
|
||||
|
||||
@@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::{
|
||||
self, Flags, GenericArgsRef, Region, RegionVid, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
|
||||
self, GenericArgsRef, Region, RegionVid, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
|
||||
TypeVisitor,
|
||||
};
|
||||
use tracing::{debug, instrument};
|
||||
@@ -177,7 +177,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for CollectMemberConstraintsVisitor<'_, '_,
|
||||
| ty::Coroutine(def_id, args) => self.visit_closure_args(def_id, args),
|
||||
|
||||
ty::Alias(ty::AliasTy { kind, args, .. })
|
||||
if let Some(variances) = self.cx().opt_alias_variances(kind) =>
|
||||
if let Some(variances) = self.cx().opt_alias_variances(kind, kind.def_id()) =>
|
||||
{
|
||||
// Skip lifetime parameters that are not captured, since they do
|
||||
// not need member constraints registered for them; we'll erase
|
||||
|
||||
@@ -10,9 +10,9 @@ use rustc_infer::traits::ObligationCause;
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::mir::{Body, ConstraintCategory};
|
||||
use rustc_middle::ty::{
|
||||
self, DefiningScopeKind, DefinitionSiteHiddenType, FallibleTypeFolder, Flags, GenericArg,
|
||||
self, DefiningScopeKind, DefinitionSiteHiddenType, FallibleTypeFolder, GenericArg,
|
||||
GenericArgsRef, OpaqueTypeKey, ProvisionalHiddenType, Region, RegionVid, Ty, TyCtxt,
|
||||
TypeFoldable, TypeSuperFoldable, TypeVisitableExt, Unnormalized, fold_regions,
|
||||
TypeFoldable, TypeSuperFoldable, TypeVisitableExt, fold_regions,
|
||||
};
|
||||
use rustc_mir_dataflow::points::DenseLocationMap;
|
||||
use rustc_span::Span;
|
||||
@@ -501,7 +501,7 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for ToArgRegionsFolder<'_, 'tcx> {
|
||||
}
|
||||
|
||||
ty::Alias(ty::AliasTy { kind, args, .. })
|
||||
if let Some(variances) = tcx.opt_alias_variances(kind) =>
|
||||
if let Some(variances) = tcx.opt_alias_variances(kind, kind.def_id()) =>
|
||||
{
|
||||
let args = tcx.mk_args_from_iter(std::iter::zip(variances, args.iter()).map(
|
||||
|(&v, s)| {
|
||||
@@ -569,17 +569,16 @@ pub(crate) fn apply_definition_site_hidden_types<'tcx>(
|
||||
};
|
||||
|
||||
// We erase all non-member region of the opaque and need to treat these as existentials.
|
||||
let expected_ty = ty::fold_regions(
|
||||
tcx,
|
||||
expected.ty.instantiate(tcx, key.args).skip_norm_wip(),
|
||||
|re, _dbi| match re.kind() {
|
||||
ty::ReErased => infcx.next_nll_region_var(
|
||||
NllRegionVariableOrigin::Existential { name: None },
|
||||
|| crate::RegionCtxt::Existential(None),
|
||||
),
|
||||
_ => re,
|
||||
},
|
||||
);
|
||||
let expected_ty =
|
||||
ty::fold_regions(tcx, expected.ty.instantiate(tcx, key.args), |re, _dbi| {
|
||||
match re.kind() {
|
||||
ty::ReErased => infcx.next_nll_region_var(
|
||||
NllRegionVariableOrigin::Existential { name: None },
|
||||
|| crate::RegionCtxt::Existential(None),
|
||||
),
|
||||
_ => re,
|
||||
}
|
||||
});
|
||||
|
||||
// We now simply equate the expected with the actual hidden type.
|
||||
let locations = Locations::All(hidden_type.span);
|
||||
@@ -599,13 +598,8 @@ pub(crate) fn apply_definition_site_hidden_types<'tcx>(
|
||||
body.source.def_id().expect_local(),
|
||||
);
|
||||
// We need to normalize both types in the old solver before equatingt them.
|
||||
let actual_ty = ocx.normalize(
|
||||
&cause,
|
||||
infcx.param_env,
|
||||
Unnormalized::new_wip(hidden_type.ty),
|
||||
);
|
||||
let expected_ty =
|
||||
ocx.normalize(&cause, infcx.param_env, Unnormalized::new_wip(expected_ty));
|
||||
let actual_ty = ocx.normalize(&cause, infcx.param_env, hidden_type.ty);
|
||||
let expected_ty = ocx.normalize(&cause, infcx.param_env, expected_ty);
|
||||
ocx.eq(&cause, infcx.param_env, actual_ty, expected_ty).map_err(|_| NoSolution)
|
||||
},
|
||||
"equating opaque types",
|
||||
|
||||
@@ -5,7 +5,7 @@ use rustc_infer::infer::canonical::Canonical;
|
||||
use rustc_infer::infer::outlives::env::RegionBoundPairs;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::{Body, ConstraintCategory};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, Unnormalized, Upcast};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, Upcast};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_trait_selection::solve::NoSolution;
|
||||
@@ -189,11 +189,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
where
|
||||
T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
|
||||
{
|
||||
self.normalize_with_category(
|
||||
Unnormalized::new_wip(value),
|
||||
location,
|
||||
ConstraintCategory::Boring,
|
||||
)
|
||||
self.normalize_with_category(value, location, ConstraintCategory::Boring)
|
||||
}
|
||||
|
||||
pub(super) fn deeply_normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
|
||||
@@ -211,14 +207,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub(super) fn normalize_with_category<T>(
|
||||
&mut self,
|
||||
value: Unnormalized<'tcx, T>,
|
||||
value: T,
|
||||
location: impl NormalizeLocation,
|
||||
category: ConstraintCategory<'tcx>,
|
||||
) -> T
|
||||
where
|
||||
T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
|
||||
{
|
||||
let value = value.skip_normalization();
|
||||
let param_env = self.infcx.param_env;
|
||||
let result: Result<_, ErrorGuaranteed> = self.fully_perform_op(
|
||||
location.to_locations(),
|
||||
@@ -251,7 +246,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
CustomTypeOp::new(
|
||||
|ocx| {
|
||||
let structurally_normalize = |ty| {
|
||||
ocx.structurally_normalize_ty(&cause, param_env, Unnormalized::new_wip(ty))
|
||||
ocx.structurally_normalize_ty(
|
||||
&cause,
|
||||
param_env,
|
||||
ty,
|
||||
)
|
||||
.unwrap_or_else(|_| bug!("struct tail should have been computable, since we computed it in HIR"))
|
||||
};
|
||||
|
||||
@@ -296,7 +295,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
body.source.def_id().expect_local(),
|
||||
),
|
||||
param_env,
|
||||
Unnormalized::new_wip(ty),
|
||||
ty,
|
||||
)
|
||||
.map_err(|_| NoSolution)
|
||||
},
|
||||
@@ -365,7 +364,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
// obligation for the unnormalized user_ty here. This is
|
||||
// where the "incorrectly skips the WF checks we normally do"
|
||||
// happens
|
||||
let user_ty = ocx.normalize(&cause, param_env, Unnormalized::new_wip(user_ty));
|
||||
let user_ty = ocx.normalize(&cause, param_env, user_ty);
|
||||
ocx.eq(&cause, param_env, user_ty, mir_ty)?;
|
||||
Ok(())
|
||||
},
|
||||
|
||||
@@ -70,14 +70,12 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub(super) fn convert_all(&mut self, query_constraints: &QueryRegionConstraints<'tcx>) {
|
||||
let QueryRegionConstraints { constraints, assumptions } = query_constraints;
|
||||
let QueryRegionConstraints { outlives, assumptions } = query_constraints;
|
||||
let assumptions =
|
||||
elaborate::elaborate_outlives_assumptions(self.infcx.tcx, assumptions.iter().copied());
|
||||
|
||||
for &(constraint, constraint_category) in constraints {
|
||||
constraint.iter_outlives().for_each(|predicate| {
|
||||
self.convert(predicate, constraint_category, &assumptions);
|
||||
});
|
||||
for &(predicate, constraint_category) in outlives {
|
||||
self.convert(predicate, constraint_category, &assumptions);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,12 +292,8 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||
) {
|
||||
Ok(TypeOpOutput { output: ty, constraints, .. }) => {
|
||||
// FIXME(higher_ranked_auto): What should we do with the assumptions here?
|
||||
if let Some(QueryRegionConstraints { constraints, assumptions: _ }) = constraints {
|
||||
next_outlives_predicates.extend(constraints.iter().flat_map(
|
||||
|(constraint, category)| {
|
||||
constraint.iter_outlives().map(|outlives| (outlives, *category))
|
||||
},
|
||||
));
|
||||
if let Some(QueryRegionConstraints { outlives, assumptions: _ }) = constraints {
|
||||
next_outlives_predicates.extend(outlives.iter().copied());
|
||||
}
|
||||
ty
|
||||
}
|
||||
|
||||
@@ -32,15 +32,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the MIR body was constructed via `construct_error` (because an
|
||||
// earlier pass like match checking failed), its args may not match
|
||||
// the user-provided signature (e.g. a coroutine with too many
|
||||
// parameters). Bail out as this can cause panic,
|
||||
// see <https://github.com/rust-lang/rust/issues/139570>.
|
||||
if self.body.tainted_by_errors.is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
let user_provided_poly_sig = self.tcx().closure_user_provided_sig(mir_def_id);
|
||||
|
||||
// Instantiate the canonicalized variables from user-provided signature
|
||||
@@ -103,7 +94,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
user_provided_sig = self.tcx().mk_fn_sig(
|
||||
user_provided_sig.inputs().iter().copied(),
|
||||
output_ty,
|
||||
user_provided_sig.fn_sig_kind,
|
||||
user_provided_sig.c_variadic,
|
||||
user_provided_sig.safety,
|
||||
user_provided_sig.abi,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user