Merge ref 'f6d23413c3' from rust-lang/rust
Pull recent changes from https://github.com/rust-lang/rust via Josh.
Upstream ref: f6d23413c3
Filtered ref: fc132ae45e682a2556f99caed7bca9b8a2e909c8
This merge was created using https://github.com/rust-lang/josh-sync.
This commit is contained in:
commit
005dc5cbdc
614 changed files with 10961 additions and 5595 deletions
258
Cargo.lock
258
Cargo.lock
|
|
@ -152,9 +152,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.98"
|
||||
version = "1.0.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
||||
checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
|
||||
|
||||
[[package]]
|
||||
name = "ar_archive_writer"
|
||||
|
|
@ -204,7 +204,7 @@ dependencies = [
|
|||
"rustc-hash 2.1.1",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -266,9 +266,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.9.1"
|
||||
version = "2.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
|
||||
checksum = "6a65b545ab31d687cff52899d4890855fec459eb6afe0da6417b8a18da87aa29"
|
||||
|
||||
[[package]]
|
||||
name = "blake3"
|
||||
|
|
@ -315,7 +315,7 @@ dependencies = [
|
|||
"serde_json",
|
||||
"sha2",
|
||||
"tar",
|
||||
"toml 0.5.11",
|
||||
"toml 0.7.8",
|
||||
"xz2",
|
||||
]
|
||||
|
||||
|
|
@ -336,7 +336,7 @@ dependencies = [
|
|||
"curl",
|
||||
"indexmap",
|
||||
"serde",
|
||||
"toml 0.5.11",
|
||||
"toml 0.7.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -421,7 +421,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde-untagged",
|
||||
"serde-value",
|
||||
"thiserror 2.0.12",
|
||||
"thiserror 2.0.15",
|
||||
"toml 0.8.23",
|
||||
"unicode-xid",
|
||||
"url",
|
||||
|
|
@ -453,7 +453,7 @@ dependencies = [
|
|||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 2.0.12",
|
||||
"thiserror 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -518,9 +518,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.43"
|
||||
version = "4.5.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50fd97c9dc2399518aa331917ac6f274280ec5eb34e555dd291899745c48ec6f"
|
||||
checksum = "1fc0e74a703892159f5ae7d3aac52c8e6c392f5ae5f359c70b5881d60aaac318"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
|
@ -538,9 +538,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.43"
|
||||
version = "4.5.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c35b5830294e1fa0462034af85cc95225a4cb07092c088c55bda3147cfcd8f65"
|
||||
checksum = "b3e7f4214277f3c7aa526a59dd3fbe306a370daee1f8b7b8c987069cd8e888a8"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
|
|
@ -550,14 +550,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.41"
|
||||
version = "4.5.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491"
|
||||
checksum = "14cb31bb0a7d536caef2639baa7fad459e15c3144efefa6dbd1c84562c4739f6"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -720,7 +720,7 @@ dependencies = [
|
|||
"nom",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -907,9 +907,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "curl"
|
||||
version = "0.4.48"
|
||||
version = "0.4.49"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e2d5c8f48d9c0c23250e52b55e82a6ab4fdba6650c931f5a0a57a43abda812b"
|
||||
checksum = "79fc3b6dd0b87ba36e565715bf9a2ced221311db47bd18011676f24a6066edbc"
|
||||
dependencies = [
|
||||
"curl-sys",
|
||||
"libc",
|
||||
|
|
@ -922,9 +922,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "curl-sys"
|
||||
version = "0.4.82+curl-8.14.1"
|
||||
version = "0.4.83+curl-8.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4d63638b5ec65f1a4ae945287b3fd035be4554bbaf211901159c9a2a74fb5be"
|
||||
checksum = "5830daf304027db10c82632a464879d46a3f7c4ba17a31592657ad16c719b483"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
|
|
@ -937,9 +937,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cxx"
|
||||
version = "1.0.166"
|
||||
version = "1.0.168"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5287274dfdf7e7eaa3d97d460eb2a94922539e6af214bda423f292105011ee2"
|
||||
checksum = "7aa144b12f11741f0dab5b4182896afad46faa0598b6a061f7b9d17a21837ba7"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cxxbridge-cmd",
|
||||
|
|
@ -951,9 +951,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cxx-build"
|
||||
version = "1.0.166"
|
||||
version = "1.0.168"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "65f3ce027a744135db10a1ebffa0863dab685aeef48f40a02c201f5e70c667d3"
|
||||
checksum = "12d3cbb84fb003242941c231b45ca9417e786e66e94baa39584bd99df3a270b6"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"codespan-reporting",
|
||||
|
|
@ -961,40 +961,40 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"scratch",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-cmd"
|
||||
version = "1.0.166"
|
||||
version = "1.0.168"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a07dc23f2eea4774297f4c9a17ae4065fecb63127da556e6c9fadb0216d93595"
|
||||
checksum = "3fa36b7b249d43f67a3f54bd65788e35e7afe64bbc671396387a48b3e8aaea94"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"codespan-reporting",
|
||||
"indexmap",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-flags"
|
||||
version = "1.0.166"
|
||||
version = "1.0.168"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7a4dbad6171f763c4066c83dcd27546b6e93c5c5ae2229f9813bda7233f571d"
|
||||
checksum = "77707c70f6563edc5429618ca34a07241b75ebab35bd01d46697c75d58f8ddfe"
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-macro"
|
||||
version = "1.0.166"
|
||||
version = "1.0.168"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9be4b527950fc42db06163705e78e73eedc8fd723708e942afe3572a9a2c366"
|
||||
checksum = "ede6c0fb7e318f0a11799b86ee29dcf17b9be2960bd379a6c38e1a96a6010fff"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1018,7 +1018,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1029,7 +1029,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
|
|||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1061,7 +1061,7 @@ checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1082,7 +1082,7 @@ dependencies = [
|
|||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1092,7 +1092,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
|
||||
dependencies = [
|
||||
"derive_builder_core",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1104,7 +1104,7 @@ dependencies = [
|
|||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1129,16 +1129,16 @@ version = "6.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d"
|
||||
dependencies = [
|
||||
"dirs-sys 0.5.0",
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "5.0.1"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
|
||||
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
|
||||
dependencies = [
|
||||
"dirs-sys 0.4.1",
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1151,18 +1151,6 @@ dependencies = [
|
|||
"dirs-sys-next",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users 0.4.6",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.5.0"
|
||||
|
|
@ -1194,7 +1182,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1379,7 +1367,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "54f0d287c53ffd184d04d8677f590f4ac5379785529e5e08b1c8083acdd5c198"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"thiserror 2.0.12",
|
||||
"thiserror 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1539,9 +1527,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.2"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
|
||||
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
|
||||
|
||||
[[package]]
|
||||
name = "globset"
|
||||
|
|
@ -1855,7 +1843,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2044,7 +2032,7 @@ checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2102,7 +2090,7 @@ dependencies = [
|
|||
"pest_derive",
|
||||
"regex",
|
||||
"serde_json",
|
||||
"thiserror 2.0.12",
|
||||
"thiserror 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2337,7 +2325,7 @@ checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2643,9 +2631,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.37.2"
|
||||
version = "0.37.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3e3d0a7419f081f4a808147e845310313a39f322d7ae1f996b7f001d6cbed04"
|
||||
checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"flate2",
|
||||
|
|
@ -2653,7 +2641,7 @@ dependencies = [
|
|||
"indexmap",
|
||||
"memchr",
|
||||
"ruzstd 0.8.1",
|
||||
"wasmparser 0.236.0",
|
||||
"wasmparser 0.236.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2834,7 +2822,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"thiserror 2.0.12",
|
||||
"thiserror 2.0.15",
|
||||
"ucd-trie",
|
||||
]
|
||||
|
||||
|
|
@ -2858,7 +2846,7 @@ dependencies = [
|
|||
"pest_meta",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3007,9 +2995,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.95"
|
||||
version = "1.0.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
|
||||
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
|
@ -3147,9 +3135,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.10.0"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
|
||||
checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
|
|
@ -3157,9 +3145,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.12.1"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
|
||||
checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
|
|
@ -3193,7 +3181,7 @@ checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
|
|||
dependencies = [
|
||||
"getrandom 0.2.16",
|
||||
"libredox",
|
||||
"thiserror 2.0.12",
|
||||
"thiserror 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3279,11 +3267,11 @@ dependencies = [
|
|||
"build_helper",
|
||||
"gimli 0.32.0",
|
||||
"libc",
|
||||
"object 0.37.2",
|
||||
"object 0.37.3",
|
||||
"regex",
|
||||
"serde_json",
|
||||
"similar",
|
||||
"wasmparser 0.236.0",
|
||||
"wasmparser 0.236.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3459,7 +3447,6 @@ dependencies = [
|
|||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_macros",
|
||||
"rustc_parse",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
|
|
@ -3490,6 +3477,7 @@ dependencies = [
|
|||
"rustc_hir",
|
||||
"rustc_lexer",
|
||||
"rustc_macros",
|
||||
"rustc_parse",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"thin-vec",
|
||||
|
|
@ -3570,7 +3558,7 @@ dependencies = [
|
|||
"itertools",
|
||||
"libc",
|
||||
"measureme",
|
||||
"object 0.37.2",
|
||||
"object 0.37.3",
|
||||
"rustc-demangle",
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
|
|
@ -3608,7 +3596,7 @@ dependencies = [
|
|||
"cc",
|
||||
"itertools",
|
||||
"libc",
|
||||
"object 0.37.2",
|
||||
"object 0.37.3",
|
||||
"pathdiff",
|
||||
"regex",
|
||||
"rustc_abi",
|
||||
|
|
@ -3797,6 +3785,7 @@ dependencies = [
|
|||
"annotate-snippets 0.11.5",
|
||||
"derive_setters",
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
"rustc_error_codes",
|
||||
"rustc_error_messages",
|
||||
|
|
@ -3863,7 +3852,7 @@ dependencies = [
|
|||
"fluent-syntax",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
"unic-langid",
|
||||
]
|
||||
|
||||
|
|
@ -4023,7 +4012,7 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4134,7 +4123,6 @@ dependencies = [
|
|||
name = "rustc_lint_defs"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
"rustc_error_messages",
|
||||
|
|
@ -4169,7 +4157,7 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
|
|
@ -4355,7 +4343,6 @@ dependencies = [
|
|||
"rustc-literal-escaper",
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_attr_parsing",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
|
|
@ -4654,7 +4641,7 @@ name = "rustc_target"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"object 0.37.2",
|
||||
"object 0.37.3",
|
||||
"rustc_abi",
|
||||
"rustc_data_structures",
|
||||
"rustc_error_messages",
|
||||
|
|
@ -4792,7 +4779,7 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
|
|
@ -4884,7 +4871,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5021,9 +5008,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde-untagged"
|
||||
version = "0.1.7"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "299d9c19d7d466db4ab10addd5703e4c615dec2a5a16dbbafe191045e87ee66e"
|
||||
checksum = "34836a629bcbc6f1afdf0907a744870039b1e14c0561cb26094fa683b158eff3"
|
||||
dependencies = [
|
||||
"erased-serde",
|
||||
"serde",
|
||||
|
|
@ -5048,7 +5035,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5139,12 +5126,12 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
|||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.5.10"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
|
||||
checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5284,9 +5271,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.104"
|
||||
version = "2.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
|
||||
checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -5301,7 +5288,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5419,11 +5406,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.12"
|
||||
version = "2.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||
checksum = "80d76d3f064b981389ecb4b6b7f45a0bf9fdac1d5b9204c7bd6714fecc302850"
|
||||
dependencies = [
|
||||
"thiserror-impl 2.0.12",
|
||||
"thiserror-impl 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5434,18 +5421,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.12"
|
||||
version = "2.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||
checksum = "44d29feb33e986b6ea906bd9c3559a856983f92371b3eaa5e83782a351623de0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5546,15 +5533,6 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.7.8"
|
||||
|
|
@ -5642,7 +5620,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5825,7 +5803,7 @@ checksum = "a1249a628de3ad34b821ecb1001355bca3940bcb2f88558f1a8bd82e977f75b5"
|
|||
dependencies = [
|
||||
"proc-macro-hack",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
"unic-langid-impl",
|
||||
]
|
||||
|
||||
|
|
@ -5957,9 +5935,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
|||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.17.0"
|
||||
version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
|
||||
checksum = "f33196643e165781c20a5ead5582283a7dacbb87855d867fbc2df3f81eddc1be"
|
||||
dependencies = [
|
||||
"getrandom 0.3.3",
|
||||
"js-sys",
|
||||
|
|
@ -6037,7 +6015,7 @@ dependencies = [
|
|||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
|
|
@ -6059,7 +6037,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
|
@ -6122,12 +6100,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.236.0"
|
||||
version = "0.236.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3108979166ab0d3c7262d2e16a2190ffe784b2a5beb963edef154b5e8e07680b"
|
||||
checksum = "724fccfd4f3c24b7e589d333fc0429c68042897a7e8a5f8694f31792471841e7"
|
||||
dependencies = [
|
||||
"leb128fmt",
|
||||
"wasmparser 0.236.0",
|
||||
"wasmparser 0.236.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6167,9 +6145,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.236.0"
|
||||
version = "0.236.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16d1eee846a705f6f3cb9d7b9f79b54583810f1fb57a1e3aea76d1742db2e3d2"
|
||||
checksum = "a9b1e81f3eb254cf7404a82cee6926a4a3ccc5aad80cc3d43608a070c67aa1d7"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"indexmap",
|
||||
|
|
@ -6178,22 +6156,22 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wast"
|
||||
version = "236.0.0"
|
||||
version = "236.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11d6b6faeab519ba6fbf9b26add41617ca6f5553f99ebc33d876e591d2f4f3c6"
|
||||
checksum = "d3bec4b4db9c6808d394632fd4b0cd4654c32c540bd3237f55ee6a40fff6e51f"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"leb128fmt",
|
||||
"memchr",
|
||||
"unicode-width 0.2.1",
|
||||
"wasm-encoder 0.236.0",
|
||||
"wasm-encoder 0.236.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wat"
|
||||
version = "1.236.0"
|
||||
version = "1.236.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc31704322400f461f7f31a5f9190d5488aaeafb63ae69ad2b5888d2704dcb08"
|
||||
checksum = "64475e2f77d6071ce90624098fc236285ddafa8c3ea1fb386f2c4154b6c2bbdb"
|
||||
dependencies = [
|
||||
"wast",
|
||||
]
|
||||
|
|
@ -6327,7 +6305,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6338,7 +6316,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6349,7 +6327,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6360,7 +6338,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6793,7 +6771,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
|
|
@ -6805,7 +6783,7 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
|
|
@ -6826,7 +6804,7 @@ checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6846,7 +6824,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
|
|
@ -6891,7 +6869,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6902,5 +6880,5 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ pub use NtPatKind::*;
|
|||
pub use TokenKind::*;
|
||||
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::symbol::IdentPrintMode;
|
||||
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, kw, sym};
|
||||
#[allow(clippy::useless_attribute)] // FIXME: following use of `hidden_glob_reexports` incorrectly triggers `useless_attribute` lint.
|
||||
#[allow(hidden_glob_reexports)]
|
||||
|
|
@ -344,15 +345,24 @@ pub enum IdentIsRaw {
|
|||
Yes,
|
||||
}
|
||||
|
||||
impl From<bool> for IdentIsRaw {
|
||||
fn from(b: bool) -> Self {
|
||||
if b { Self::Yes } else { Self::No }
|
||||
impl IdentIsRaw {
|
||||
pub fn to_print_mode_ident(self) -> IdentPrintMode {
|
||||
match self {
|
||||
IdentIsRaw::No => IdentPrintMode::Normal,
|
||||
IdentIsRaw::Yes => IdentPrintMode::RawIdent,
|
||||
}
|
||||
}
|
||||
pub fn to_print_mode_lifetime(self) -> IdentPrintMode {
|
||||
match self {
|
||||
IdentIsRaw::No => IdentPrintMode::Normal,
|
||||
IdentIsRaw::Yes => IdentPrintMode::RawLifetime,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IdentIsRaw> for bool {
|
||||
fn from(is_raw: IdentIsRaw) -> bool {
|
||||
matches!(is_raw, IdentIsRaw::Yes)
|
||||
impl From<bool> for IdentIsRaw {
|
||||
fn from(b: bool) -> Self {
|
||||
if b { Self::Yes } else { Self::No }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1596,7 +1596,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let safety = self.lower_safety(h.safety, default_safety);
|
||||
|
||||
// Treat safe `#[target_feature]` functions as unsafe, but also remember that we did so.
|
||||
let safety = if find_attr!(attrs, AttributeKind::TargetFeature { .. })
|
||||
let safety = if find_attr!(attrs, AttributeKind::TargetFeature { was_forced: false, .. })
|
||||
&& safety.is_safe()
|
||||
&& !self.tcx.sess.target.is_like_wasm
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ rustc_errors = { path = "../rustc_errors" }
|
|||
rustc_feature = { path = "../rustc_feature" }
|
||||
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_parse = { path = "../rustc_parse" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
|
|
|
|||
|
|
@ -113,6 +113,10 @@ ast_passes_extern_without_abi = `extern` declarations without an explicit ABI ar
|
|||
.suggestion = specify an ABI
|
||||
.help = prior to Rust 2024, a default ABI was inferred
|
||||
|
||||
ast_passes_extern_without_abi_sugg = `extern` declarations without an explicit ABI are deprecated
|
||||
.label = ABI should be specified here
|
||||
.suggestion = explicitly specify the {$default_abi} ABI
|
||||
|
||||
ast_passes_feature_on_non_nightly = `#![feature]` may not be used on the {$channel} release channel
|
||||
.suggestion = remove the attribute
|
||||
.stable_since = the feature `{$name}` has been stable since `{$since}` and no longer requires an attribute to enable
|
||||
|
|
|
|||
|
|
@ -25,16 +25,16 @@ use rustc_abi::{CanonAbi, ExternAbi, InterruptKind};
|
|||
use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, walk_list};
|
||||
use rustc_ast::*;
|
||||
use rustc_ast_pretty::pprust::{self, State};
|
||||
use rustc_attr_parsing::validate_attr;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_errors::{DiagCtxtHandle, LintBuffer};
|
||||
use rustc_feature::Features;
|
||||
use rustc_parse::validate_attr;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::lint::BuiltinLintDiag;
|
||||
use rustc_session::lint::builtin::{
|
||||
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN,
|
||||
PATTERNS_IN_FNS_WITHOUT_BODY,
|
||||
};
|
||||
use rustc_session::lint::{BuiltinLintDiag, LintBuffer};
|
||||
use rustc_span::{Ident, Span, kw, sym};
|
||||
use rustc_target::spec::{AbiMap, AbiMapping};
|
||||
use thin_vec::thin_vec;
|
||||
|
|
@ -876,7 +876,7 @@ impl<'a> AstValidator<'a> {
|
|||
MISSING_ABI,
|
||||
id,
|
||||
span,
|
||||
BuiltinLintDiag::MissingAbi(span, ExternAbi::FALLBACK),
|
||||
errors::MissingAbiSugg { span, default_abi: ExternAbi::FALLBACK },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use rustc_abi::ExternAbi;
|
|||
use rustc_ast::ParamKindOrd;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
||||
use rustc_span::{Ident, Span, Symbol};
|
||||
|
||||
use crate::fluent_generated as fluent;
|
||||
|
|
@ -815,6 +815,14 @@ pub(crate) struct MissingAbi {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(ast_passes_extern_without_abi_sugg)]
|
||||
pub(crate) struct MissingAbiSugg {
|
||||
#[suggestion(code = "extern {default_abi}", applicability = "machine-applicable")]
|
||||
pub span: Span,
|
||||
pub default_abi: ExternAbi,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_abi_custom_safe_foreign_function)]
|
||||
pub(crate) struct AbiCustomSafeForeignFunction {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use std::borrow::Cow;
|
|||
use std::sync::Arc;
|
||||
|
||||
use rustc_ast::attr::AttrIdGenerator;
|
||||
use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind};
|
||||
use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind};
|
||||
use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree};
|
||||
use rustc_ast::util::classify;
|
||||
use rustc_ast::util::comments::{Comment, CommentStyle};
|
||||
|
|
@ -441,7 +441,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool);
|
||||
|
||||
fn print_ident(&mut self, ident: Ident) {
|
||||
self.word(IdentPrinter::for_ast_ident(ident, ident.is_raw_guess()).to_string());
|
||||
self.word(IdentPrinter::for_ast_ident(ident, ident.guess_print_mode()).to_string());
|
||||
self.ann_post(ident)
|
||||
}
|
||||
|
||||
|
|
@ -1015,17 +1015,16 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
|
||||
/* Name components */
|
||||
token::Ident(name, is_raw) => {
|
||||
IdentPrinter::new(name, is_raw.into(), convert_dollar_crate).to_string().into()
|
||||
IdentPrinter::new(name, is_raw.to_print_mode_ident(), convert_dollar_crate)
|
||||
.to_string()
|
||||
.into()
|
||||
}
|
||||
token::NtIdent(ident, is_raw) => {
|
||||
IdentPrinter::for_ast_ident(ident, is_raw.into()).to_string().into()
|
||||
IdentPrinter::for_ast_ident(ident, is_raw.to_print_mode_ident()).to_string().into()
|
||||
}
|
||||
|
||||
token::Lifetime(name, IdentIsRaw::No)
|
||||
| token::NtLifetime(Ident { name, .. }, IdentIsRaw::No) => name.to_string().into(),
|
||||
token::Lifetime(name, IdentIsRaw::Yes)
|
||||
| token::NtLifetime(Ident { name, .. }, IdentIsRaw::Yes) => {
|
||||
format!("'r#{}", &name.as_str()[1..]).into()
|
||||
token::Lifetime(name, is_raw) | token::NtLifetime(Ident { name, .. }, is_raw) => {
|
||||
IdentPrinter::new(name, is_raw.to_print_mode_lifetime(), None).to_string().into()
|
||||
}
|
||||
|
||||
/* Other */
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
|||
rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_lexer = { path = "../rustc_lexer" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_parse = { path = "../rustc_parse" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
thin-vec = "0.2.12"
|
||||
|
|
|
|||
|
|
@ -170,3 +170,22 @@ attr_parsing_unused_multiple =
|
|||
|
||||
-attr_parsing_previously_accepted =
|
||||
this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
|
||||
attr_parsing_meta_bad_delim = wrong meta list delimiters
|
||||
attr_parsing_meta_bad_delim_suggestion = the delimiters should be `(` and `)`
|
||||
|
||||
attr_parsing_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe
|
||||
.label = usage of unsafe attribute
|
||||
attr_parsing_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)`
|
||||
|
||||
attr_parsing_invalid_attr_unsafe = `{$name}` is not an unsafe attribute
|
||||
.label = this is not an unsafe attribute
|
||||
.suggestion = remove the `unsafe(...)`
|
||||
.note = extraneous unsafe is not allowed in attributes
|
||||
|
||||
attr_parsing_invalid_meta_item = expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found {$descr}
|
||||
.remove_neg_sugg = negative numbers are not literals, try removing the `-` sign
|
||||
.quote_ident_sugg = surround the identifier with quotation marks to make it into a string literal
|
||||
|
||||
attr_parsing_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes
|
||||
.help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, UsedBy};
|
||||
use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, SanitizerSet, UsedBy};
|
||||
use rustc_session::parse::feature_err;
|
||||
|
||||
use super::prelude::*;
|
||||
|
|
@ -35,7 +35,7 @@ impl<S: Stage> SingleAttributeParser<S> for OptimizeParser {
|
|||
Some(sym::speed) => OptimizeAttr::Speed,
|
||||
Some(sym::none) => OptimizeAttr::DoNotOptimize,
|
||||
_ => {
|
||||
cx.expected_specific_argument(single.span(), vec!["size", "speed", "none"]);
|
||||
cx.expected_specific_argument(single.span(), &[sym::size, sym::speed, sym::none]);
|
||||
OptimizeAttr::Default
|
||||
}
|
||||
};
|
||||
|
|
@ -82,7 +82,7 @@ impl<S: Stage> SingleAttributeParser<S> for CoverageParser {
|
|||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
let Some(args) = args.list() else {
|
||||
cx.expected_specific_argument_and_list(cx.attr_span, vec!["on", "off"]);
|
||||
cx.expected_specific_argument_and_list(cx.attr_span, &[sym::on, sym::off]);
|
||||
return None;
|
||||
};
|
||||
|
||||
|
|
@ -91,7 +91,8 @@ impl<S: Stage> SingleAttributeParser<S> for CoverageParser {
|
|||
return None;
|
||||
};
|
||||
|
||||
let fail_incorrect_argument = |span| cx.expected_specific_argument(span, vec!["on", "off"]);
|
||||
let fail_incorrect_argument =
|
||||
|span| cx.expected_specific_argument(span, &[sym::on, sym::off]);
|
||||
|
||||
let Some(arg) = arg.meta_item() else {
|
||||
fail_incorrect_argument(args.span);
|
||||
|
|
@ -343,7 +344,7 @@ impl<S: Stage> AttributeParser<S> for UsedParser {
|
|||
UsedBy::Linker
|
||||
}
|
||||
_ => {
|
||||
cx.expected_specific_argument(l.span(), vec!["compiler", "linker"]);
|
||||
cx.expected_specific_argument(l.span(), &[sym::compiler, sym::linker]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -376,57 +377,68 @@ impl<S: Stage> AttributeParser<S> for UsedParser {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_tf_attribute<'c, S: Stage>(
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
args: &'c ArgParser<'_>,
|
||||
) -> impl IntoIterator<Item = (Symbol, Span)> + 'c {
|
||||
let mut features = Vec::new();
|
||||
let ArgParser::List(list) = args else {
|
||||
cx.expected_list(cx.attr_span);
|
||||
return features;
|
||||
};
|
||||
if list.is_empty() {
|
||||
cx.warn_empty_attribute(cx.attr_span);
|
||||
return features;
|
||||
}
|
||||
for item in list.mixed() {
|
||||
let Some(name_value) = item.meta_item() else {
|
||||
cx.expected_name_value(item.span(), Some(sym::enable));
|
||||
return features;
|
||||
};
|
||||
|
||||
// Validate name
|
||||
let Some(name) = name_value.path().word_sym() else {
|
||||
cx.expected_name_value(name_value.path().span(), Some(sym::enable));
|
||||
return features;
|
||||
};
|
||||
if name != sym::enable {
|
||||
cx.expected_name_value(name_value.path().span(), Some(sym::enable));
|
||||
return features;
|
||||
}
|
||||
|
||||
// Use value
|
||||
let Some(name_value) = name_value.args().name_value() else {
|
||||
cx.expected_name_value(item.span(), Some(sym::enable));
|
||||
return features;
|
||||
};
|
||||
let Some(value_str) = name_value.value_as_str() else {
|
||||
cx.expected_string_literal(name_value.value_span, Some(name_value.value_as_lit()));
|
||||
return features;
|
||||
};
|
||||
for feature in value_str.as_str().split(",") {
|
||||
features.push((Symbol::intern(feature), item.span()));
|
||||
}
|
||||
}
|
||||
features
|
||||
}
|
||||
|
||||
pub(crate) struct TargetFeatureParser;
|
||||
|
||||
impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
|
||||
type Item = (Symbol, Span);
|
||||
const PATH: &[Symbol] = &[sym::target_feature];
|
||||
const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature(items, span);
|
||||
const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature {
|
||||
features: items,
|
||||
attr_span: span,
|
||||
was_forced: false,
|
||||
};
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["enable = \"feat1, feat2\""]);
|
||||
|
||||
fn extend<'c>(
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
args: &'c ArgParser<'_>,
|
||||
) -> impl IntoIterator<Item = Self::Item> + 'c {
|
||||
let mut features = Vec::new();
|
||||
let ArgParser::List(list) = args else {
|
||||
cx.expected_list(cx.attr_span);
|
||||
return features;
|
||||
};
|
||||
if list.is_empty() {
|
||||
cx.warn_empty_attribute(cx.attr_span);
|
||||
return features;
|
||||
}
|
||||
for item in list.mixed() {
|
||||
let Some(name_value) = item.meta_item() else {
|
||||
cx.expected_name_value(item.span(), Some(sym::enable));
|
||||
return features;
|
||||
};
|
||||
|
||||
// Validate name
|
||||
let Some(name) = name_value.path().word_sym() else {
|
||||
cx.expected_name_value(name_value.path().span(), Some(sym::enable));
|
||||
return features;
|
||||
};
|
||||
if name != sym::enable {
|
||||
cx.expected_name_value(name_value.path().span(), Some(sym::enable));
|
||||
return features;
|
||||
}
|
||||
|
||||
// Use value
|
||||
let Some(name_value) = name_value.args().name_value() else {
|
||||
cx.expected_name_value(item.span(), Some(sym::enable));
|
||||
return features;
|
||||
};
|
||||
let Some(value_str) = name_value.value_as_str() else {
|
||||
cx.expected_string_literal(name_value.value_span, Some(name_value.value_as_lit()));
|
||||
return features;
|
||||
};
|
||||
for feature in value_str.as_str().split(",") {
|
||||
features.push((Symbol::intern(feature), item.span()));
|
||||
}
|
||||
}
|
||||
features
|
||||
parse_tf_attribute(cx, args)
|
||||
}
|
||||
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
|
|
@ -440,3 +452,131 @@ impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
|
|||
Warn(Target::MacroDef),
|
||||
]);
|
||||
}
|
||||
|
||||
pub(crate) struct ForceTargetFeatureParser;
|
||||
|
||||
impl<S: Stage> CombineAttributeParser<S> for ForceTargetFeatureParser {
|
||||
type Item = (Symbol, Span);
|
||||
const PATH: &[Symbol] = &[sym::force_target_feature];
|
||||
const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature {
|
||||
features: items,
|
||||
attr_span: span,
|
||||
was_forced: true,
|
||||
};
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["enable = \"feat1, feat2\""]);
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
||||
]);
|
||||
|
||||
fn extend<'c>(
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
args: &'c ArgParser<'_>,
|
||||
) -> impl IntoIterator<Item = Self::Item> + 'c {
|
||||
parse_tf_attribute(cx, args)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct SanitizeParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for SanitizeParser {
|
||||
const PATH: &[Symbol] = &[sym::sanitize];
|
||||
|
||||
// FIXME: still checked in check_attrs.rs
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
|
||||
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &[
|
||||
r#"address = "on|off""#,
|
||||
r#"kernel_address = "on|off""#,
|
||||
r#"cfi = "on|off""#,
|
||||
r#"hwaddress = "on|off""#,
|
||||
r#"kcfi = "on|off""#,
|
||||
r#"memory = "on|off""#,
|
||||
r#"memtag = "on|off""#,
|
||||
r#"shadow_call_stack = "on|off""#,
|
||||
r#"thread = "on|off""#
|
||||
]);
|
||||
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
let Some(list) = args.list() else {
|
||||
cx.expected_list(cx.attr_span);
|
||||
return None;
|
||||
};
|
||||
|
||||
let mut on_set = SanitizerSet::empty();
|
||||
let mut off_set = SanitizerSet::empty();
|
||||
|
||||
for item in list.mixed() {
|
||||
let Some(item) = item.meta_item() else {
|
||||
cx.expected_name_value(item.span(), None);
|
||||
continue;
|
||||
};
|
||||
|
||||
let path = item.path().word_sym();
|
||||
let Some(value) = item.args().name_value() else {
|
||||
cx.expected_name_value(item.span(), path);
|
||||
continue;
|
||||
};
|
||||
|
||||
let mut apply = |s: SanitizerSet| {
|
||||
let is_on = match value.value_as_str() {
|
||||
Some(sym::on) => true,
|
||||
Some(sym::off) => false,
|
||||
Some(_) => {
|
||||
cx.expected_specific_argument_strings(
|
||||
value.value_span,
|
||||
&[sym::on, sym::off],
|
||||
);
|
||||
return;
|
||||
}
|
||||
None => {
|
||||
cx.expected_string_literal(value.value_span, Some(value.value_as_lit()));
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if is_on {
|
||||
on_set |= s;
|
||||
} else {
|
||||
off_set |= s;
|
||||
}
|
||||
};
|
||||
|
||||
match path {
|
||||
Some(sym::address) | Some(sym::kernel_address) => {
|
||||
apply(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS)
|
||||
}
|
||||
Some(sym::cfi) => apply(SanitizerSet::CFI),
|
||||
Some(sym::kcfi) => apply(SanitizerSet::KCFI),
|
||||
Some(sym::memory) => apply(SanitizerSet::MEMORY),
|
||||
Some(sym::memtag) => apply(SanitizerSet::MEMTAG),
|
||||
Some(sym::shadow_call_stack) => apply(SanitizerSet::SHADOWCALLSTACK),
|
||||
Some(sym::thread) => apply(SanitizerSet::THREAD),
|
||||
Some(sym::hwaddress) => apply(SanitizerSet::HWADDRESS),
|
||||
_ => {
|
||||
cx.expected_specific_argument_strings(
|
||||
item.path().span(),
|
||||
&[
|
||||
sym::address,
|
||||
sym::cfi,
|
||||
sym::kcfi,
|
||||
sym::memory,
|
||||
sym::memtag,
|
||||
sym::shadow_call_stack,
|
||||
sym::thread,
|
||||
sym::hwaddress,
|
||||
],
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(AttributeKind::Sanitize { on_set, off_set, span: cx.attr_span })
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ impl<S: Stage> SingleAttributeParser<S> for InlineParser {
|
|||
Some(AttributeKind::Inline(InlineAttr::Never, cx.attr_span))
|
||||
}
|
||||
_ => {
|
||||
cx.expected_specific_argument(l.span(), vec!["always", "never"]);
|
||||
cx.expected_specific_argument(l.span(), &[sym::always, sym::never]);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -206,16 +206,16 @@ impl<S: Stage> SingleAttributeParser<S> for LinkageParser {
|
|||
_ => {
|
||||
cx.expected_specific_argument(
|
||||
name_value.value_span,
|
||||
vec![
|
||||
"available_externally",
|
||||
"common",
|
||||
"extern_weak",
|
||||
"external",
|
||||
"internal",
|
||||
"linkonce",
|
||||
"linkonce_odr",
|
||||
"weak",
|
||||
"weak_odr",
|
||||
&[
|
||||
sym::available_externally,
|
||||
sym::common,
|
||||
sym::extern_weak,
|
||||
sym::external,
|
||||
sym::internal,
|
||||
sym::linkonce,
|
||||
sym::linkonce_odr,
|
||||
sym::weak,
|
||||
sym::weak_odr,
|
||||
],
|
||||
);
|
||||
return None;
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ fn parse_derive_like<S: Stage>(
|
|||
return None;
|
||||
};
|
||||
if !attr_list.path().word_is(sym::attributes) {
|
||||
cx.expected_specific_argument(attrs.span(), vec!["attributes"]);
|
||||
cx.expected_specific_argument(attrs.span(), &[sym::attributes]);
|
||||
return None;
|
||||
}
|
||||
let Some(attr_list) = attr_list.args().list() else {
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ fn parse_dialect<S: Stage>(
|
|||
sym::runtime => MirDialect::Runtime,
|
||||
|
||||
_ => {
|
||||
cx.expected_specific_argument(span, vec!["analysis", "built", "runtime"]);
|
||||
cx.expected_specific_argument(span, &[sym::analysis, sym::built, sym::runtime]);
|
||||
*failed = true;
|
||||
return None;
|
||||
}
|
||||
|
|
@ -131,7 +131,7 @@ fn parse_phase<S: Stage>(
|
|||
sym::optimized => MirPhase::Optimized,
|
||||
|
||||
_ => {
|
||||
cx.expected_specific_argument(span, vec!["initial", "post-cleanup", "optimized"]);
|
||||
cx.expected_specific_argument(span, &[sym::initial, sym::post_cleanup, sym::optimized]);
|
||||
*failed = true;
|
||||
return None;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ impl<S: Stage> SingleAttributeParser<S> for ShouldPanicParser {
|
|||
return None;
|
||||
};
|
||||
if !single.path().word_is(sym::expected) {
|
||||
cx.expected_specific_argument_strings(list.span, vec!["expected"]);
|
||||
cx.expected_specific_argument_strings(list.span, &[sym::expected]);
|
||||
return None;
|
||||
}
|
||||
let Some(nv) = single.args().name_value() else {
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ impl<S: Stage> SingleAttributeParser<S> for SkipDuringMethodDispatchParser {
|
|||
Some(key @ sym::array) => (key, &mut array),
|
||||
Some(key @ sym::boxed_slice) => (key, &mut boxed_slice),
|
||||
_ => {
|
||||
cx.expected_specific_argument(path.span(), vec!["array", "boxed_slice"]);
|
||||
cx.expected_specific_argument(path.span(), &[sym::array, sym::boxed_slice]);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
|
|||
Some(_) => {
|
||||
cx.expected_specific_argument_strings(
|
||||
nv.value_span,
|
||||
vec!["transparent", "semitransparent", "opaque"],
|
||||
&[sym::transparent, sym::semitransparent, sym::opaque],
|
||||
);
|
||||
None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,8 +19,9 @@ use crate::attributes::allow_unstable::{
|
|||
};
|
||||
use crate::attributes::body::CoroutineParser;
|
||||
use crate::attributes::codegen_attrs::{
|
||||
ColdParser, CoverageParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser,
|
||||
TargetFeatureParser, TrackCallerParser, UsedParser,
|
||||
ColdParser, CoverageParser, ExportNameParser, ForceTargetFeatureParser, NakedParser,
|
||||
NoMangleParser, OptimizeParser, SanitizeParser, TargetFeatureParser, TrackCallerParser,
|
||||
UsedParser,
|
||||
};
|
||||
use crate::attributes::confusables::ConfusablesParser;
|
||||
use crate::attributes::deprecation::DeprecationParser;
|
||||
|
|
@ -157,6 +158,7 @@ attribute_parsers!(
|
|||
// tidy-alphabetical-start
|
||||
Combine<AllowConstFnUnstableParser>,
|
||||
Combine<AllowInternalUnstableParser>,
|
||||
Combine<ForceTargetFeatureParser>,
|
||||
Combine<ReprParser>,
|
||||
Combine<TargetFeatureParser>,
|
||||
Combine<UnstableFeatureBoundParser>,
|
||||
|
|
@ -183,6 +185,7 @@ attribute_parsers!(
|
|||
Single<RustcLayoutScalarValidRangeEnd>,
|
||||
Single<RustcLayoutScalarValidRangeStart>,
|
||||
Single<RustcObjectLifetimeDefaultParser>,
|
||||
Single<SanitizeParser>,
|
||||
Single<ShouldPanicParser>,
|
||||
Single<SkipDuringMethodDispatchParser>,
|
||||
Single<TransparencyParser>,
|
||||
|
|
@ -502,10 +505,11 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
|||
})
|
||||
}
|
||||
|
||||
/// produces an error along the lines of `expected one of [foo, meow]`
|
||||
pub(crate) fn expected_specific_argument(
|
||||
&self,
|
||||
span: Span,
|
||||
possibilities: Vec<&'static str>,
|
||||
possibilities: &[Symbol],
|
||||
) -> ErrorGuaranteed {
|
||||
self.emit_err(AttributeParseError {
|
||||
span,
|
||||
|
|
@ -521,10 +525,12 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
|||
})
|
||||
}
|
||||
|
||||
/// produces an error along the lines of `expected one of [foo, meow] as an argument`.
|
||||
/// i.e. slightly different wording to [`expected_specific_argument`](Self::expected_specific_argument).
|
||||
pub(crate) fn expected_specific_argument_and_list(
|
||||
&self,
|
||||
span: Span,
|
||||
possibilities: Vec<&'static str>,
|
||||
possibilities: &[Symbol],
|
||||
) -> ErrorGuaranteed {
|
||||
self.emit_err(AttributeParseError {
|
||||
span,
|
||||
|
|
@ -540,10 +546,11 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
|||
})
|
||||
}
|
||||
|
||||
/// produces an error along the lines of `expected one of ["foo", "meow"]`
|
||||
pub(crate) fn expected_specific_argument_strings(
|
||||
&self,
|
||||
span: Span,
|
||||
possibilities: Vec<&'static str>,
|
||||
possibilities: &[Symbol],
|
||||
) -> ErrorGuaranteed {
|
||||
self.emit_err(AttributeParseError {
|
||||
span,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::NodeId;
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
|
|
@ -49,27 +51,44 @@ impl<'sess> AttributeParser<'sess, Early> {
|
|||
target_node_id: NodeId,
|
||||
features: Option<&'sess Features>,
|
||||
) -> Option<Attribute> {
|
||||
let mut p = Self {
|
||||
features,
|
||||
tools: Vec::new(),
|
||||
parse_only: Some(sym),
|
||||
let mut parsed = Self::parse_limited_all(
|
||||
sess,
|
||||
stage: Early { emit_errors: ShouldEmit::Nothing },
|
||||
};
|
||||
let mut parsed = p.parse_attribute_list(
|
||||
attrs,
|
||||
Some(sym),
|
||||
Target::Crate, // Does not matter, we're not going to emit errors anyways
|
||||
target_span,
|
||||
target_node_id,
|
||||
features,
|
||||
ShouldEmit::Nothing,
|
||||
);
|
||||
assert!(parsed.len() <= 1);
|
||||
parsed.pop()
|
||||
}
|
||||
|
||||
pub fn parse_limited_all(
|
||||
sess: &'sess Session,
|
||||
attrs: &[ast::Attribute],
|
||||
parse_only: Option<Symbol>,
|
||||
target: Target,
|
||||
target_span: Span,
|
||||
target_node_id: NodeId,
|
||||
features: Option<&'sess Features>,
|
||||
emit_errors: ShouldEmit,
|
||||
) -> Vec<Attribute> {
|
||||
let mut p =
|
||||
Self { features, tools: Vec::new(), parse_only, sess, stage: Early { emit_errors } };
|
||||
p.parse_attribute_list(
|
||||
attrs,
|
||||
target_span,
|
||||
target_node_id,
|
||||
Target::Crate, // Does not matter, we're not going to emit errors anyways
|
||||
target,
|
||||
OmitDoc::Skip,
|
||||
std::convert::identity,
|
||||
|_lint| {
|
||||
panic!("can't emit lints here for now (nothing uses this atm)");
|
||||
// FIXME: Can't emit lints here for now
|
||||
// This branch can be hit when an attribute produces a warning during early parsing (such as attributes on macro calls)
|
||||
},
|
||||
);
|
||||
assert!(parsed.len() <= 1);
|
||||
|
||||
parsed.pop()
|
||||
)
|
||||
}
|
||||
|
||||
pub fn parse_single<T>(
|
||||
|
|
@ -79,9 +98,9 @@ impl<'sess> AttributeParser<'sess, Early> {
|
|||
target_node_id: NodeId,
|
||||
features: Option<&'sess Features>,
|
||||
emit_errors: ShouldEmit,
|
||||
parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> T,
|
||||
parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> Option<T>,
|
||||
template: &AttributeTemplate,
|
||||
) -> T {
|
||||
) -> Option<T> {
|
||||
let mut parser = Self {
|
||||
features,
|
||||
tools: Vec::new(),
|
||||
|
|
@ -92,7 +111,9 @@ impl<'sess> AttributeParser<'sess, Early> {
|
|||
let ast::AttrKind::Normal(normal_attr) = &attr.kind else {
|
||||
panic!("parse_single called on a doc attr")
|
||||
};
|
||||
let meta_parser = MetaItemParser::from_attr(normal_attr, parser.dcx());
|
||||
let parts =
|
||||
normal_attr.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>();
|
||||
let meta_parser = MetaItemParser::from_attr(normal_attr, &parts, &sess.psess, emit_errors)?;
|
||||
let path = meta_parser.path();
|
||||
let args = meta_parser.args();
|
||||
let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
|
||||
|
|
@ -199,14 +220,22 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
// }))
|
||||
// }
|
||||
ast::AttrKind::Normal(n) => {
|
||||
attr_paths.push(PathParser::Ast(&n.item.path));
|
||||
attr_paths.push(PathParser(Cow::Borrowed(&n.item.path)));
|
||||
|
||||
let parser = MetaItemParser::from_attr(n, self.dcx());
|
||||
let path = parser.path();
|
||||
let args = parser.args();
|
||||
let path_parts = path.segments().map(|i| i.name).collect::<Vec<_>>();
|
||||
let parts =
|
||||
n.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>();
|
||||
|
||||
if let Some(accepts) = S::parsers().accepters.get(path_parts.as_slice()) {
|
||||
if let Some(accepts) = S::parsers().accepters.get(parts.as_slice()) {
|
||||
let Some(parser) = MetaItemParser::from_attr(
|
||||
n,
|
||||
&parts,
|
||||
&self.sess.psess,
|
||||
self.stage.should_emit(),
|
||||
) else {
|
||||
continue;
|
||||
};
|
||||
let path = parser.path();
|
||||
let args = parser.args();
|
||||
for accept in accepts {
|
||||
let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
|
||||
shared: SharedContext {
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ pub mod parser;
|
|||
mod lints;
|
||||
mod session_diagnostics;
|
||||
mod target_checking;
|
||||
pub mod validate_attr;
|
||||
|
||||
pub use attributes::cfg::{CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg_attr};
|
||||
pub use attributes::cfg_old::*;
|
||||
|
|
|
|||
|
|
@ -3,45 +3,30 @@
|
|||
//!
|
||||
//! FIXME(jdonszelmann): delete `rustc_ast/attr/mod.rs`
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::fmt::{Debug, Display};
|
||||
use std::iter::Peekable;
|
||||
|
||||
use rustc_ast::token::{self, Delimiter, Token};
|
||||
use rustc_ast::tokenstream::{TokenStreamIter, TokenTree};
|
||||
use rustc_ast::token::{self, Delimiter, MetaVarKind};
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{AttrArgs, DelimArgs, Expr, ExprKind, LitKind, MetaItemLit, NormalAttr, Path};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_errors::PResult;
|
||||
use rustc_hir::{self as hir, AttrPath};
|
||||
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym};
|
||||
use rustc_parse::exp;
|
||||
use rustc_parse::parser::{Parser, PathStyle, token_descr};
|
||||
use rustc_session::errors::report_lit_error;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, sym};
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
pub struct SegmentIterator<'a> {
|
||||
offset: usize,
|
||||
path: &'a PathParser<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for SegmentIterator<'a> {
|
||||
type Item = &'a Ident;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.offset >= self.path.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let res = match self.path {
|
||||
PathParser::Ast(ast_path) => &ast_path.segments[self.offset].ident,
|
||||
PathParser::Attr(attr_path) => &attr_path.segments[self.offset],
|
||||
};
|
||||
|
||||
self.offset += 1;
|
||||
Some(res)
|
||||
}
|
||||
}
|
||||
use crate::ShouldEmit;
|
||||
use crate::session_diagnostics::{
|
||||
InvalidMetaItem, InvalidMetaItemQuoteIdentSugg, InvalidMetaItemRemoveNegSugg, MetaBadDelim,
|
||||
MetaBadDelimSugg, SuffixedLiteralInAttribute,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum PathParser<'a> {
|
||||
Ast(&'a Path),
|
||||
Attr(AttrPath),
|
||||
}
|
||||
pub struct PathParser<'a>(pub Cow<'a, Path>);
|
||||
|
||||
impl<'a> PathParser<'a> {
|
||||
pub fn get_attribute_path(&self) -> hir::AttrPath {
|
||||
|
|
@ -52,21 +37,15 @@ impl<'a> PathParser<'a> {
|
|||
}
|
||||
|
||||
pub fn segments(&'a self) -> impl Iterator<Item = &'a Ident> {
|
||||
SegmentIterator { offset: 0, path: self }
|
||||
self.0.segments.iter().map(|seg| &seg.ident)
|
||||
}
|
||||
|
||||
pub fn span(&self) -> Span {
|
||||
match self {
|
||||
PathParser::Ast(path) => path.span,
|
||||
PathParser::Attr(attr_path) => attr_path.span,
|
||||
}
|
||||
self.0.span
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
match self {
|
||||
PathParser::Ast(path) => path.segments.len(),
|
||||
PathParser::Attr(attr_path) => attr_path.segments.len(),
|
||||
}
|
||||
self.0.segments.len()
|
||||
}
|
||||
|
||||
pub fn segments_is(&self, segments: &[Symbol]) -> bool {
|
||||
|
|
@ -99,10 +78,7 @@ impl<'a> PathParser<'a> {
|
|||
|
||||
impl Display for PathParser<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
PathParser::Ast(path) => write!(f, "{}", pprust::path_to_string(path)),
|
||||
PathParser::Attr(attr_path) => write!(f, "{attr_path}"),
|
||||
}
|
||||
write!(f, "{}", pprust::path_to_string(&self.0))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -123,21 +99,39 @@ impl<'a> ArgParser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn from_attr_args<'sess>(value: &'a AttrArgs, dcx: DiagCtxtHandle<'sess>) -> Self {
|
||||
match value {
|
||||
pub fn from_attr_args<'sess>(
|
||||
value: &'a AttrArgs,
|
||||
parts: &[Symbol],
|
||||
psess: &'sess ParseSess,
|
||||
should_emit: ShouldEmit,
|
||||
) -> Option<Self> {
|
||||
Some(match value {
|
||||
AttrArgs::Empty => Self::NoArgs,
|
||||
AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
|
||||
Self::List(MetaItemListParser::new(args, dcx))
|
||||
}
|
||||
AttrArgs::Delimited(args) => {
|
||||
Self::List(MetaItemListParser { sub_parsers: vec![], span: args.dspan.entire() })
|
||||
// The arguments of rustc_dummy are not validated if the arguments are delimited
|
||||
if parts == &[sym::rustc_dummy] {
|
||||
return Some(ArgParser::List(MetaItemListParser {
|
||||
sub_parsers: ThinVec::new(),
|
||||
span: args.dspan.entire(),
|
||||
}));
|
||||
}
|
||||
|
||||
if args.delim != Delimiter::Parenthesis {
|
||||
psess.dcx().emit_err(MetaBadDelim {
|
||||
span: args.dspan.entire(),
|
||||
sugg: MetaBadDelimSugg { open: args.dspan.open, close: args.dspan.close },
|
||||
});
|
||||
return None;
|
||||
}
|
||||
|
||||
Self::List(MetaItemListParser::new(args, psess, should_emit)?)
|
||||
}
|
||||
AttrArgs::Eq { eq_span, expr } => Self::NameValue(NameValueParser {
|
||||
eq_span: *eq_span,
|
||||
value: expr_to_lit(dcx, &expr, *eq_span),
|
||||
value: expr_to_lit(psess, &expr, expr.span, should_emit)?,
|
||||
value_span: expr.span,
|
||||
}),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Asserts that this MetaItem is a list
|
||||
|
|
@ -249,11 +243,16 @@ impl<'a> Debug for MetaItemParser<'a> {
|
|||
impl<'a> MetaItemParser<'a> {
|
||||
/// Create a new parser from a [`NormalAttr`], which is stored inside of any
|
||||
/// [`ast::Attribute`](rustc_ast::Attribute)
|
||||
pub fn from_attr<'sess>(attr: &'a NormalAttr, dcx: DiagCtxtHandle<'sess>) -> Self {
|
||||
Self {
|
||||
path: PathParser::Ast(&attr.item.path),
|
||||
args: ArgParser::from_attr_args(&attr.item.args, dcx),
|
||||
}
|
||||
pub fn from_attr<'sess>(
|
||||
attr: &'a NormalAttr,
|
||||
parts: &[Symbol],
|
||||
psess: &'sess ParseSess,
|
||||
should_emit: ShouldEmit,
|
||||
) -> Option<Self> {
|
||||
Some(Self {
|
||||
path: PathParser(Cow::Borrowed(&attr.item.path)),
|
||||
args: ArgParser::from_attr_args(&attr.item.args, parts, psess, should_emit)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -318,215 +317,232 @@ impl NameValueParser {
|
|||
}
|
||||
}
|
||||
|
||||
fn expr_to_lit(dcx: DiagCtxtHandle<'_>, expr: &Expr, span: Span) -> MetaItemLit {
|
||||
// In valid code the value always ends up as a single literal. Otherwise, a dummy
|
||||
// literal suffices because the error is handled elsewhere.
|
||||
if let ExprKind::Lit(token_lit) = expr.kind
|
||||
&& let Ok(lit) = MetaItemLit::from_token_lit(token_lit, expr.span)
|
||||
{
|
||||
lit
|
||||
fn expr_to_lit(
|
||||
psess: &ParseSess,
|
||||
expr: &Expr,
|
||||
span: Span,
|
||||
should_emit: ShouldEmit,
|
||||
) -> Option<MetaItemLit> {
|
||||
if let ExprKind::Lit(token_lit) = expr.kind {
|
||||
let res = MetaItemLit::from_token_lit(token_lit, expr.span);
|
||||
match res {
|
||||
Ok(lit) => {
|
||||
if token_lit.suffix.is_some() {
|
||||
psess
|
||||
.dcx()
|
||||
.create_err(SuffixedLiteralInAttribute { span: lit.span })
|
||||
.emit_unless_delay(!should_emit.should_emit());
|
||||
None
|
||||
} else {
|
||||
if should_emit.should_emit() && !lit.kind.is_unsuffixed() {
|
||||
// Emit error and continue, we can still parse the attribute as if the suffix isn't there
|
||||
psess.dcx().emit_err(SuffixedLiteralInAttribute { span: lit.span });
|
||||
}
|
||||
|
||||
Some(lit)
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
let guar = report_lit_error(psess, err, token_lit, expr.span);
|
||||
let lit = MetaItemLit {
|
||||
symbol: token_lit.symbol,
|
||||
suffix: token_lit.suffix,
|
||||
kind: LitKind::Err(guar),
|
||||
span: expr.span,
|
||||
};
|
||||
Some(lit)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let guar = dcx.span_delayed_bug(
|
||||
span,
|
||||
"expr in place where literal is expected (builtin attr parsing)",
|
||||
);
|
||||
MetaItemLit { symbol: sym::dummy, suffix: None, kind: LitKind::Err(guar), span }
|
||||
// Example cases:
|
||||
// - `#[foo = 1+1]`: results in `ast::ExprKind::BinOp`.
|
||||
// - `#[foo = include_str!("nonexistent-file.rs")]`:
|
||||
// results in `ast::ExprKind::Err`. In that case we delay
|
||||
// the error because an earlier error will have already
|
||||
// been reported.
|
||||
let msg = "attribute value must be a literal";
|
||||
let mut err = psess.dcx().struct_span_err(span, msg);
|
||||
if let ExprKind::Err(_) = expr.kind {
|
||||
err.downgrade_to_delayed_bug();
|
||||
}
|
||||
|
||||
err.emit_unless_delay(!should_emit.should_emit());
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
struct MetaItemListParserContext<'a, 'sess> {
|
||||
// the tokens inside the delimiters, so `#[some::attr(a b c)]` would have `a b c` inside
|
||||
inside_delimiters: Peekable<TokenStreamIter<'a>>,
|
||||
dcx: DiagCtxtHandle<'sess>,
|
||||
parser: &'a mut Parser<'sess>,
|
||||
should_emit: ShouldEmit,
|
||||
}
|
||||
|
||||
impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
|
||||
fn done(&mut self) -> bool {
|
||||
self.inside_delimiters.peek().is_none()
|
||||
}
|
||||
fn parse_unsuffixed_meta_item_lit(&mut self) -> PResult<'sess, MetaItemLit> {
|
||||
let uninterpolated_span = self.parser.token_uninterpolated_span();
|
||||
let Some(token_lit) = self.parser.eat_token_lit() else {
|
||||
return self.parser.handle_missing_lit(Parser::mk_meta_item_lit_char);
|
||||
};
|
||||
|
||||
fn next_path(&mut self) -> Option<AttrPath> {
|
||||
// FIXME: Share code with `parse_path`.
|
||||
let tt = self.inside_delimiters.next().map(|tt| TokenTree::uninterpolate(tt));
|
||||
|
||||
match tt.as_deref()? {
|
||||
&TokenTree::Token(
|
||||
Token { kind: ref kind @ (token::Ident(..) | token::PathSep), span },
|
||||
_,
|
||||
) => {
|
||||
// here we have either an ident or pathsep `::`.
|
||||
|
||||
let mut segments = if let &token::Ident(name, _) = kind {
|
||||
// when we lookahead another pathsep, more path's coming
|
||||
if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) =
|
||||
self.inside_delimiters.peek()
|
||||
{
|
||||
self.inside_delimiters.next();
|
||||
vec![Ident::new(name, span)]
|
||||
} else {
|
||||
// else we have a single identifier path, that's all
|
||||
return Some(AttrPath {
|
||||
segments: vec![Ident::new(name, span)].into_boxed_slice(),
|
||||
span,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// if `::` is all we get, we just got a path root
|
||||
vec![Ident::new(kw::PathRoot, span)]
|
||||
};
|
||||
|
||||
// one segment accepted. accept n more
|
||||
loop {
|
||||
// another ident?
|
||||
if let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) =
|
||||
self.inside_delimiters
|
||||
.next()
|
||||
.map(|tt| TokenTree::uninterpolate(tt))
|
||||
.as_deref()
|
||||
{
|
||||
segments.push(Ident::new(name, span));
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
// stop unless we see another `::`
|
||||
if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) =
|
||||
self.inside_delimiters.peek()
|
||||
{
|
||||
self.inside_delimiters.next();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let span = span.with_hi(segments.last().unwrap().span.hi());
|
||||
Some(AttrPath { segments: segments.into_boxed_slice(), span })
|
||||
let lit = match MetaItemLit::from_token_lit(token_lit, self.parser.prev_token.span) {
|
||||
Ok(lit) => lit,
|
||||
Err(err) => {
|
||||
let guar =
|
||||
report_lit_error(&self.parser.psess, err, token_lit, uninterpolated_span);
|
||||
// Pack possible quotes and prefixes from the original literal into
|
||||
// the error literal's symbol so they can be pretty-printed faithfully.
|
||||
let suffixless_lit = token::Lit::new(token_lit.kind, token_lit.symbol, None);
|
||||
let symbol = Symbol::intern(&suffixless_lit.to_string());
|
||||
let token_lit = token::Lit::new(token::Err(guar), symbol, token_lit.suffix);
|
||||
MetaItemLit::from_token_lit(token_lit, uninterpolated_span).unwrap()
|
||||
}
|
||||
TokenTree::Token(Token { kind, .. }, _) if kind.is_delim() => None,
|
||||
_ => {
|
||||
// malformed attributes can get here. We can't crash, but somewhere else should've
|
||||
// already warned for this.
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fn value(&mut self) -> Option<MetaItemLit> {
|
||||
match self.inside_delimiters.next() {
|
||||
Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
|
||||
MetaItemListParserContext {
|
||||
inside_delimiters: inner_tokens.iter().peekable(),
|
||||
dcx: self.dcx,
|
||||
}
|
||||
.value()
|
||||
}
|
||||
Some(TokenTree::Token(token, _)) => MetaItemLit::from_token(token),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// parses one element on the inside of a list attribute like `#[my_attr( <insides> )]`
|
||||
///
|
||||
/// parses a path followed be either:
|
||||
/// 1. nothing (a word attr)
|
||||
/// 2. a parenthesized list
|
||||
/// 3. an equals sign and a literal (name-value)
|
||||
///
|
||||
/// Can also parse *just* a literal. This is for cases like as `#[my_attr("literal")]`
|
||||
/// where no path is given before the literal
|
||||
///
|
||||
/// Some exceptions too for interpolated attributes which are already pre-processed
|
||||
fn next(&mut self) -> Option<MetaItemOrLitParser<'a>> {
|
||||
// a list element is either a literal
|
||||
if let Some(TokenTree::Token(token, _)) = self.inside_delimiters.peek()
|
||||
&& let Some(lit) = MetaItemLit::from_token(token)
|
||||
{
|
||||
self.inside_delimiters.next();
|
||||
return Some(MetaItemOrLitParser::Lit(lit));
|
||||
} else if let Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) =
|
||||
self.inside_delimiters.peek()
|
||||
{
|
||||
self.inside_delimiters.next();
|
||||
return MetaItemListParserContext {
|
||||
inside_delimiters: inner_tokens.iter().peekable(),
|
||||
dcx: self.dcx,
|
||||
}
|
||||
.next();
|
||||
if self.should_emit.should_emit() && !lit.kind.is_unsuffixed() {
|
||||
// Emit error and continue, we can still parse the attribute as if the suffix isn't there
|
||||
self.parser.dcx().emit_err(SuffixedLiteralInAttribute { span: lit.span });
|
||||
}
|
||||
|
||||
// or a path.
|
||||
let path = self.next_path()?;
|
||||
|
||||
// Paths can be followed by:
|
||||
// - `(more meta items)` (another list)
|
||||
// - `= lit` (a name-value)
|
||||
// - nothing
|
||||
Some(MetaItemOrLitParser::MetaItemParser(match self.inside_delimiters.peek() {
|
||||
Some(TokenTree::Delimited(dspan, _, Delimiter::Parenthesis, inner_tokens)) => {
|
||||
self.inside_delimiters.next();
|
||||
|
||||
MetaItemParser {
|
||||
path: PathParser::Attr(path),
|
||||
args: ArgParser::List(MetaItemListParser::new_tts(
|
||||
inner_tokens.iter(),
|
||||
dspan.entire(),
|
||||
self.dcx,
|
||||
)),
|
||||
}
|
||||
}
|
||||
Some(TokenTree::Delimited(_, ..)) => {
|
||||
self.inside_delimiters.next();
|
||||
// self.dcx.span_delayed_bug(span.entire(), "wrong delimiters");
|
||||
return None;
|
||||
}
|
||||
Some(TokenTree::Token(Token { kind: token::Eq, span }, _)) => {
|
||||
self.inside_delimiters.next();
|
||||
let value = self.value()?;
|
||||
MetaItemParser {
|
||||
path: PathParser::Attr(path),
|
||||
args: ArgParser::NameValue(NameValueParser {
|
||||
eq_span: *span,
|
||||
value_span: value.span,
|
||||
value,
|
||||
}),
|
||||
}
|
||||
}
|
||||
_ => MetaItemParser { path: PathParser::Attr(path), args: ArgParser::NoArgs },
|
||||
}))
|
||||
Ok(lit)
|
||||
}
|
||||
|
||||
fn parse(mut self, span: Span) -> MetaItemListParser<'a> {
|
||||
let mut sub_parsers = Vec::new();
|
||||
|
||||
while !self.done() {
|
||||
let Some(n) = self.next() else {
|
||||
continue;
|
||||
fn parse_attr_item(&mut self) -> PResult<'sess, MetaItemParser<'static>> {
|
||||
if let Some(MetaVarKind::Meta { has_meta_form }) = self.parser.token.is_metavar_seq() {
|
||||
return if has_meta_form {
|
||||
let attr_item = self
|
||||
.parser
|
||||
.eat_metavar_seq(MetaVarKind::Meta { has_meta_form: true }, |this| {
|
||||
MetaItemListParserContext { parser: this, should_emit: self.should_emit }
|
||||
.parse_attr_item()
|
||||
})
|
||||
.unwrap();
|
||||
Ok(attr_item)
|
||||
} else {
|
||||
self.parser.unexpected_any()
|
||||
};
|
||||
sub_parsers.push(n);
|
||||
}
|
||||
|
||||
match self.inside_delimiters.peek() {
|
||||
None | Some(TokenTree::Token(Token { kind: token::Comma, .. }, _)) => {
|
||||
self.inside_delimiters.next();
|
||||
}
|
||||
Some(_) => {}
|
||||
let path = self.parser.parse_path(PathStyle::Mod)?;
|
||||
|
||||
// Check style of arguments that this meta item has
|
||||
let args = if self.parser.check(exp!(OpenParen)) {
|
||||
let start = self.parser.token.span;
|
||||
let (sub_parsers, _) = self.parser.parse_paren_comma_seq(|parser| {
|
||||
MetaItemListParserContext { parser, should_emit: self.should_emit }
|
||||
.parse_meta_item_inner()
|
||||
})?;
|
||||
let end = self.parser.prev_token.span;
|
||||
ArgParser::List(MetaItemListParser { sub_parsers, span: start.with_hi(end.hi()) })
|
||||
} else if self.parser.eat(exp!(Eq)) {
|
||||
let eq_span = self.parser.prev_token.span;
|
||||
let value = self.parse_unsuffixed_meta_item_lit()?;
|
||||
|
||||
ArgParser::NameValue(NameValueParser { eq_span, value, value_span: value.span })
|
||||
} else {
|
||||
ArgParser::NoArgs
|
||||
};
|
||||
|
||||
Ok(MetaItemParser { path: PathParser(Cow::Owned(path)), args })
|
||||
}
|
||||
|
||||
fn parse_meta_item_inner(&mut self) -> PResult<'sess, MetaItemOrLitParser<'static>> {
|
||||
match self.parse_unsuffixed_meta_item_lit() {
|
||||
Ok(lit) => return Ok(MetaItemOrLitParser::Lit(lit)),
|
||||
Err(err) => err.cancel(), // we provide a better error below
|
||||
}
|
||||
|
||||
match self.parse_attr_item() {
|
||||
Ok(mi) => return Ok(MetaItemOrLitParser::MetaItemParser(mi)),
|
||||
Err(err) => err.cancel(), // we provide a better error below
|
||||
}
|
||||
|
||||
let mut err = InvalidMetaItem {
|
||||
span: self.parser.token.span,
|
||||
descr: token_descr(&self.parser.token),
|
||||
quote_ident_sugg: None,
|
||||
remove_neg_sugg: None,
|
||||
};
|
||||
|
||||
// Suggest quoting idents, e.g. in `#[cfg(key = value)]`. We don't use `Token::ident` and
|
||||
// don't `uninterpolate` the token to avoid suggesting anything butchered or questionable
|
||||
// when macro metavariables are involved.
|
||||
if self.parser.prev_token == token::Eq
|
||||
&& let token::Ident(..) = self.parser.token.kind
|
||||
{
|
||||
let before = self.parser.token.span.shrink_to_lo();
|
||||
while let token::Ident(..) = self.parser.token.kind {
|
||||
self.parser.bump();
|
||||
}
|
||||
err.quote_ident_sugg = Some(InvalidMetaItemQuoteIdentSugg {
|
||||
before,
|
||||
after: self.parser.prev_token.span.shrink_to_hi(),
|
||||
});
|
||||
}
|
||||
|
||||
if self.parser.token == token::Minus
|
||||
&& self
|
||||
.parser
|
||||
.look_ahead(1, |t| matches!(t.kind, rustc_ast::token::TokenKind::Literal { .. }))
|
||||
{
|
||||
err.remove_neg_sugg =
|
||||
Some(InvalidMetaItemRemoveNegSugg { negative_sign: self.parser.token.span });
|
||||
self.parser.bump();
|
||||
self.parser.bump();
|
||||
}
|
||||
|
||||
Err(self.parser.dcx().create_err(err))
|
||||
}
|
||||
|
||||
fn parse(
|
||||
tokens: TokenStream,
|
||||
psess: &'sess ParseSess,
|
||||
span: Span,
|
||||
should_emit: ShouldEmit,
|
||||
) -> PResult<'sess, MetaItemListParser<'static>> {
|
||||
let mut parser = Parser::new(psess, tokens, None);
|
||||
let mut this = MetaItemListParserContext { parser: &mut parser, should_emit };
|
||||
|
||||
// Presumably, the majority of the time there will only be one attr.
|
||||
let mut sub_parsers = ThinVec::with_capacity(1);
|
||||
while this.parser.token != token::Eof {
|
||||
sub_parsers.push(this.parse_meta_item_inner()?);
|
||||
|
||||
if !this.parser.eat(exp!(Comma)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MetaItemListParser { sub_parsers, span }
|
||||
if parser.token != token::Eof {
|
||||
parser.unexpected()?;
|
||||
}
|
||||
|
||||
Ok(MetaItemListParser { sub_parsers, span })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MetaItemListParser<'a> {
|
||||
sub_parsers: Vec<MetaItemOrLitParser<'a>>,
|
||||
sub_parsers: ThinVec<MetaItemOrLitParser<'a>>,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl<'a> MetaItemListParser<'a> {
|
||||
fn new<'sess>(delim: &'a DelimArgs, dcx: DiagCtxtHandle<'sess>) -> Self {
|
||||
MetaItemListParser::new_tts(delim.tokens.iter(), delim.dspan.entire(), dcx)
|
||||
}
|
||||
|
||||
fn new_tts<'sess>(tts: TokenStreamIter<'a>, span: Span, dcx: DiagCtxtHandle<'sess>) -> Self {
|
||||
MetaItemListParserContext { inside_delimiters: tts.peekable(), dcx }.parse(span)
|
||||
fn new<'sess>(
|
||||
delim: &'a DelimArgs,
|
||||
psess: &'sess ParseSess,
|
||||
should_emit: ShouldEmit,
|
||||
) -> Option<Self> {
|
||||
match MetaItemListParserContext::parse(
|
||||
delim.tokens.clone(),
|
||||
psess,
|
||||
delim.dspan.entire(),
|
||||
should_emit,
|
||||
) {
|
||||
Ok(s) => Some(s),
|
||||
Err(e) => {
|
||||
e.emit_unless_delay(!should_emit.should_emit());
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Lets you pick and choose as what you want to parse each element in the list
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::num::IntErrorKind;
|
||||
|
||||
use rustc_ast::{self as ast, AttrStyle};
|
||||
use rustc_ast::{self as ast, AttrStyle, Path};
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level,
|
||||
|
|
@ -558,7 +558,7 @@ pub(crate) struct LinkOrdinalOutOfRange {
|
|||
pub ordinal: u128,
|
||||
}
|
||||
|
||||
pub(crate) enum AttributeParseErrorReason {
|
||||
pub(crate) enum AttributeParseErrorReason<'a> {
|
||||
ExpectedNoArgs,
|
||||
ExpectedStringLiteral {
|
||||
byte_string: Option<Span>,
|
||||
|
|
@ -571,7 +571,7 @@ pub(crate) enum AttributeParseErrorReason {
|
|||
ExpectedNameValue(Option<Symbol>),
|
||||
DuplicateKey(Symbol),
|
||||
ExpectedSpecificArgument {
|
||||
possibilities: Vec<&'static str>,
|
||||
possibilities: &'a [Symbol],
|
||||
strings: bool,
|
||||
/// Should we tell the user to write a list when they didn't?
|
||||
list: bool,
|
||||
|
|
@ -579,16 +579,16 @@ pub(crate) enum AttributeParseErrorReason {
|
|||
ExpectedIdentifier,
|
||||
}
|
||||
|
||||
pub(crate) struct AttributeParseError {
|
||||
pub(crate) struct AttributeParseError<'a> {
|
||||
pub(crate) span: Span,
|
||||
pub(crate) attr_span: Span,
|
||||
pub(crate) attr_style: AttrStyle,
|
||||
pub(crate) template: AttributeTemplate,
|
||||
pub(crate) attribute: AttrPath,
|
||||
pub(crate) reason: AttributeParseErrorReason,
|
||||
pub(crate) reason: AttributeParseErrorReason<'a>,
|
||||
}
|
||||
|
||||
impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
|
||||
impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
|
||||
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
|
||||
let name = self.attribute.to_string();
|
||||
|
||||
|
|
@ -657,7 +657,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
|
|||
list: false,
|
||||
} => {
|
||||
let quote = if strings { '"' } else { '`' };
|
||||
match possibilities.as_slice() {
|
||||
match possibilities {
|
||||
&[] => {}
|
||||
&[x] => {
|
||||
diag.span_label(
|
||||
|
|
@ -687,7 +687,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
|
|||
list: true,
|
||||
} => {
|
||||
let quote = if strings { '"' } else { '`' };
|
||||
match possibilities.as_slice() {
|
||||
match possibilities {
|
||||
&[] => {}
|
||||
&[x] => {
|
||||
diag.span_label(
|
||||
|
|
@ -737,3 +737,92 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
|
|||
diag
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_invalid_attr_unsafe)]
|
||||
#[note]
|
||||
pub(crate) struct InvalidAttrUnsafe {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub name: Path,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_unsafe_attr_outside_unsafe)]
|
||||
pub(crate) struct UnsafeAttrOutsideUnsafe {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub suggestion: UnsafeAttrOutsideUnsafeSuggestion,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
attr_parsing_unsafe_attr_outside_unsafe_suggestion,
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion {
|
||||
#[suggestion_part(code = "unsafe(")]
|
||||
pub left: Span,
|
||||
#[suggestion_part(code = ")")]
|
||||
pub right: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_meta_bad_delim)]
|
||||
pub(crate) struct MetaBadDelim {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub sugg: MetaBadDelimSugg,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
attr_parsing_meta_bad_delim_suggestion,
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub(crate) struct MetaBadDelimSugg {
|
||||
#[suggestion_part(code = "(")]
|
||||
pub open: Span,
|
||||
#[suggestion_part(code = ")")]
|
||||
pub close: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_invalid_meta_item)]
|
||||
pub(crate) struct InvalidMetaItem {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub descr: String,
|
||||
#[subdiagnostic]
|
||||
pub quote_ident_sugg: Option<InvalidMetaItemQuoteIdentSugg>,
|
||||
#[subdiagnostic]
|
||||
pub remove_neg_sugg: Option<InvalidMetaItemRemoveNegSugg>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(attr_parsing_quote_ident_sugg, applicability = "machine-applicable")]
|
||||
pub(crate) struct InvalidMetaItemQuoteIdentSugg {
|
||||
#[suggestion_part(code = "\"")]
|
||||
pub before: Span,
|
||||
#[suggestion_part(code = "\"")]
|
||||
pub after: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(attr_parsing_remove_neg_sugg, applicability = "machine-applicable")]
|
||||
pub(crate) struct InvalidMetaItemRemoveNegSugg {
|
||||
#[suggestion_part(code = "")]
|
||||
pub negative_sign: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_suffixed_literal_in_attribute)]
|
||||
#[help]
|
||||
pub(crate) struct SuffixedLiteralInAttribute {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,16 +8,16 @@ use rustc_ast::{
|
|||
self as ast, AttrArgs, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, NodeId,
|
||||
Path, Safety,
|
||||
};
|
||||
use rustc_attr_parsing::{AttributeParser, Late};
|
||||
use rustc_errors::{Applicability, DiagCtxtHandle, FatalError, PResult};
|
||||
use rustc_feature::{AttributeSafety, AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute};
|
||||
use rustc_parse::parse_in;
|
||||
use rustc_session::errors::report_lit_error;
|
||||
use rustc_session::lint::BuiltinLintDiag;
|
||||
use rustc_session::lint::builtin::{ILL_FORMED_ATTRIBUTE_INPUT, UNSAFE_ATTR_OUTSIDE_UNSAFE};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
use crate::{errors, parse_in};
|
||||
use crate::{AttributeParser, Late, session_diagnostics as errors};
|
||||
|
||||
pub fn check_attr(psess: &ParseSess, attr: &Attribute, id: NodeId) {
|
||||
if attr.is_doc_comment() || attr.has_name(sym::cfg_trace) || attr.has_name(sym::cfg_attr_trace)
|
||||
|
|
@ -33,7 +33,10 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute, id: NodeId) {
|
|||
// Check input tokens for built-in and key-value attributes.
|
||||
match builtin_attr_info {
|
||||
// `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
|
||||
Some(BuiltinAttribute { name, template, .. }) if *name != sym::rustc_dummy => {
|
||||
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) => {
|
||||
|
|
@ -133,16 +136,6 @@ fn check_meta_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter) {
|
|||
});
|
||||
}
|
||||
|
||||
pub(super) fn check_cfg_attr_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter) {
|
||||
if let Delimiter::Parenthesis = delim {
|
||||
return;
|
||||
}
|
||||
psess.dcx().emit_err(errors::CfgAttrBadDelim {
|
||||
span: span.entire(),
|
||||
sugg: errors::MetaBadDelimSugg { open: span.open, close: span.close },
|
||||
});
|
||||
}
|
||||
|
||||
/// Checks that the given meta-item is compatible with this `AttributeTemplate`.
|
||||
fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaItemKind) -> bool {
|
||||
let is_one_allowed_subword = |items: &[MetaItemInner]| match items {
|
||||
|
|
@ -269,9 +262,6 @@ pub fn check_builtin_meta_item(
|
|||
) {
|
||||
if !is_attr_template_compatible(&template, &meta.kind) {
|
||||
// attrs with new parsers are locally validated so excluded here
|
||||
if AttributeParser::<Late>::is_parsed_attribute(slice::from_ref(&name)) {
|
||||
return;
|
||||
}
|
||||
emit_malformed_attribute(psess, style, meta.span, name, template);
|
||||
}
|
||||
|
||||
|
|
@ -300,7 +300,7 @@ fn do_mir_borrowck<'tcx>(
|
|||
def: LocalDefId,
|
||||
) -> PropagatedBorrowCheckResults<'tcx> {
|
||||
let tcx = root_cx.tcx;
|
||||
let infcx = BorrowckInferCtxt::new(tcx, def);
|
||||
let infcx = BorrowckInferCtxt::new(tcx, def, root_cx.root_def_id());
|
||||
let (input_body, promoted) = tcx.mir_promoted(def);
|
||||
let input_body: &Body<'_> = &input_body.borrow();
|
||||
let input_promoted: &IndexSlice<_, _> = &promoted.borrow();
|
||||
|
|
@ -590,12 +590,13 @@ fn get_flow_results<'a, 'tcx>(
|
|||
|
||||
pub(crate) struct BorrowckInferCtxt<'tcx> {
|
||||
pub(crate) infcx: InferCtxt<'tcx>,
|
||||
pub(crate) reg_var_to_origin: RefCell<FxIndexMap<ty::RegionVid, RegionCtxt>>,
|
||||
pub(crate) root_def_id: LocalDefId,
|
||||
pub(crate) param_env: ParamEnv<'tcx>,
|
||||
pub(crate) reg_var_to_origin: RefCell<FxIndexMap<ty::RegionVid, RegionCtxt>>,
|
||||
}
|
||||
|
||||
impl<'tcx> BorrowckInferCtxt<'tcx> {
|
||||
pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
|
||||
pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId, root_def_id: LocalDefId) -> Self {
|
||||
let typing_mode = if tcx.use_typing_mode_borrowck() {
|
||||
TypingMode::borrowck(tcx, def_id)
|
||||
} else {
|
||||
|
|
@ -603,7 +604,12 @@ impl<'tcx> BorrowckInferCtxt<'tcx> {
|
|||
};
|
||||
let infcx = tcx.infer_ctxt().build(typing_mode);
|
||||
let param_env = tcx.param_env(def_id);
|
||||
BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()), param_env }
|
||||
BorrowckInferCtxt {
|
||||
infcx,
|
||||
root_def_id,
|
||||
reg_var_to_origin: RefCell::new(Default::default()),
|
||||
param_env,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn next_region_var<F>(
|
||||
|
|
|
|||
|
|
@ -38,6 +38,10 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn root_def_id(&self) -> LocalDefId {
|
||||
self.root_def_id
|
||||
}
|
||||
|
||||
/// Collect all defining uses of opaque types inside of this typeck root. This
|
||||
/// expects the hidden type to be mapped to the definition parameters of the opaque
|
||||
/// and errors if we end up with distinct hidden types.
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ where
|
|||
let old_universe = infcx.universe();
|
||||
|
||||
let TypeOpOutput { output, constraints: query_constraints, error_info } =
|
||||
op.fully_perform(infcx, locations.span(body))?;
|
||||
op.fully_perform(infcx, infcx.root_def_id, locations.span(body))?;
|
||||
if cfg!(debug_assertions) {
|
||||
let data = infcx.take_and_reset_region_constraints();
|
||||
if !data.is_empty() {
|
||||
|
|
@ -54,7 +54,6 @@ where
|
|||
infcx,
|
||||
universal_regions,
|
||||
region_bound_pairs,
|
||||
infcx.param_env,
|
||||
known_type_outlives_obligations,
|
||||
locations,
|
||||
locations.span(body),
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_infer::infer::SubregionOrigin;
|
||||
use rustc_infer::infer::canonical::QueryRegionConstraints;
|
||||
use rustc_infer::infer::outlives::env::RegionBoundPairs;
|
||||
use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
|
||||
use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
|
||||
use rustc_infer::infer::{InferCtxt, SubregionOrigin};
|
||||
use rustc_infer::traits::query::type_op::DeeplyNormalize;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::{
|
||||
|
|
@ -18,10 +18,12 @@ use crate::constraints::OutlivesConstraint;
|
|||
use crate::region_infer::TypeTest;
|
||||
use crate::type_check::{Locations, MirTypeckRegionConstraints};
|
||||
use crate::universal_regions::UniversalRegions;
|
||||
use crate::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory};
|
||||
use crate::{
|
||||
BorrowckInferCtxt, ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory,
|
||||
};
|
||||
|
||||
pub(crate) struct ConstraintConversion<'a, 'tcx> {
|
||||
infcx: &'a InferCtxt<'tcx>,
|
||||
infcx: &'a BorrowckInferCtxt<'tcx>,
|
||||
universal_regions: &'a UniversalRegions<'tcx>,
|
||||
/// Each RBP `GK: 'a` is assumed to be true. These encode
|
||||
/// relationships like `T: 'a` that are added via implicit bounds
|
||||
|
|
@ -34,7 +36,6 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> {
|
|||
/// logic expecting to see (e.g.) `ReStatic`, and if we supplied
|
||||
/// our special inference variable there, we would mess that up.
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
locations: Locations,
|
||||
span: Span,
|
||||
|
|
@ -45,10 +46,9 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> {
|
|||
|
||||
impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||
pub(crate) fn new(
|
||||
infcx: &'a InferCtxt<'tcx>,
|
||||
infcx: &'a BorrowckInferCtxt<'tcx>,
|
||||
universal_regions: &'a UniversalRegions<'tcx>,
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
locations: Locations,
|
||||
span: Span,
|
||||
|
|
@ -59,7 +59,6 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
infcx,
|
||||
universal_regions,
|
||||
region_bound_pairs,
|
||||
param_env,
|
||||
known_type_outlives_obligations,
|
||||
locations,
|
||||
span,
|
||||
|
|
@ -286,8 +285,11 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
ConstraintCategory<'tcx>,
|
||||
)>,
|
||||
) -> Ty<'tcx> {
|
||||
match self.param_env.and(DeeplyNormalize { value: ty }).fully_perform(self.infcx, self.span)
|
||||
{
|
||||
match self.infcx.param_env.and(DeeplyNormalize { value: ty }).fully_perform(
|
||||
self.infcx,
|
||||
self.infcx.root_def_id,
|
||||
self.span,
|
||||
) {
|
||||
Ok(TypeOpOutput { output: ty, constraints, .. }) => {
|
||||
// FIXME(higher_ranked_auto): What should we do with the assumptions here?
|
||||
if let Some(QueryRegionConstraints { outlives, assumptions: _ }) = constraints {
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ use rustc_data_structures::frozen::Frozen;
|
|||
use rustc_data_structures::transitive_relation::{TransitiveRelation, TransitiveRelationBuilder};
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_infer::infer::canonical::QueryRegionConstraints;
|
||||
use rustc_infer::infer::outlives;
|
||||
use rustc_infer::infer::outlives::env::RegionBoundPairs;
|
||||
use rustc_infer::infer::region_constraints::GenericKind;
|
||||
use rustc_infer::infer::{InferCtxt, outlives};
|
||||
use rustc_infer::traits::query::type_op::DeeplyNormalize;
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::traits::query::OutlivesBound;
|
||||
|
|
@ -14,6 +14,7 @@ use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
|
|||
use tracing::{debug, instrument};
|
||||
use type_op::TypeOpOutput;
|
||||
|
||||
use crate::BorrowckInferCtxt;
|
||||
use crate::type_check::{Locations, MirTypeckRegionConstraints, constraint_conversion};
|
||||
use crate::universal_regions::UniversalRegions;
|
||||
|
||||
|
|
@ -47,14 +48,12 @@ pub(crate) struct CreateResult<'tcx> {
|
|||
}
|
||||
|
||||
pub(crate) fn create<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
universal_regions: UniversalRegions<'tcx>,
|
||||
constraints: &mut MirTypeckRegionConstraints<'tcx>,
|
||||
) -> CreateResult<'tcx> {
|
||||
UniversalRegionRelationsBuilder {
|
||||
infcx,
|
||||
param_env,
|
||||
constraints,
|
||||
universal_regions,
|
||||
region_bound_pairs: Default::default(),
|
||||
|
|
@ -177,8 +176,7 @@ impl UniversalRegionRelations<'_> {
|
|||
}
|
||||
|
||||
struct UniversalRegionRelationsBuilder<'a, 'tcx> {
|
||||
infcx: &'a InferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
infcx: &'a BorrowckInferCtxt<'tcx>,
|
||||
universal_regions: UniversalRegions<'tcx>,
|
||||
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
|
||||
|
||||
|
|
@ -205,7 +203,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
|||
|
||||
// Insert the `'a: 'b` we know from the predicates.
|
||||
// This does not consider the type-outlives.
|
||||
let param_env = self.param_env;
|
||||
let param_env = self.infcx.param_env;
|
||||
self.add_outlives_bounds(outlives::explicit_outlives_bounds(param_env));
|
||||
|
||||
// - outlives is reflexive, so `'r: 'r` for every region `'r`
|
||||
|
|
@ -263,7 +261,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
|||
let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } =
|
||||
param_env
|
||||
.and(DeeplyNormalize { value: ty })
|
||||
.fully_perform(self.infcx, span)
|
||||
.fully_perform(self.infcx, self.infcx.root_def_id, span)
|
||||
.unwrap_or_else(|guar| TypeOpOutput {
|
||||
output: Ty::new_error(self.infcx.tcx, guar),
|
||||
constraints: None,
|
||||
|
|
@ -298,8 +296,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
|||
// Add implied bounds from impl header.
|
||||
if matches!(tcx.def_kind(defining_ty_def_id), DefKind::AssocFn | DefKind::AssocConst) {
|
||||
for &(ty, _) in tcx.assumed_wf_types(tcx.local_parent(defining_ty_def_id)) {
|
||||
let result: Result<_, ErrorGuaranteed> =
|
||||
param_env.and(DeeplyNormalize { value: ty }).fully_perform(self.infcx, span);
|
||||
let result: Result<_, ErrorGuaranteed> = param_env
|
||||
.and(DeeplyNormalize { value: ty })
|
||||
.fully_perform(self.infcx, self.infcx.root_def_id, span);
|
||||
let Ok(TypeOpOutput { output: norm_ty, constraints: c, .. }) = result else {
|
||||
continue;
|
||||
};
|
||||
|
|
@ -318,7 +317,6 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
|||
self.infcx,
|
||||
&self.universal_regions,
|
||||
&self.region_bound_pairs,
|
||||
param_env,
|
||||
&known_type_outlives_obligations,
|
||||
Locations::All(span),
|
||||
span,
|
||||
|
|
@ -353,10 +351,11 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
|||
output: normalized_outlives,
|
||||
constraints: constraints_normalize,
|
||||
error_info: _,
|
||||
}) = self
|
||||
.param_env
|
||||
.and(DeeplyNormalize { value: outlives })
|
||||
.fully_perform(self.infcx, span)
|
||||
}) = self.infcx.param_env.and(DeeplyNormalize { value: outlives }).fully_perform(
|
||||
self.infcx,
|
||||
self.infcx.root_def_id,
|
||||
span,
|
||||
)
|
||||
else {
|
||||
self.infcx.dcx().delayed_bug(format!("could not normalize {outlives:?}"));
|
||||
return;
|
||||
|
|
@ -381,9 +380,10 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
|||
span: Span,
|
||||
) -> Option<&'tcx QueryRegionConstraints<'tcx>> {
|
||||
let TypeOpOutput { output: bounds, constraints, .. } = self
|
||||
.infcx
|
||||
.param_env
|
||||
.and(type_op::ImpliedOutlivesBounds { ty })
|
||||
.fully_perform(self.infcx, span)
|
||||
.fully_perform(self.infcx, self.infcx.root_def_id, span)
|
||||
.map_err(|_: ErrorGuaranteed| debug!("failed to compute implied bounds {:?}", ty))
|
||||
.ok()?;
|
||||
debug!(?bounds, ?constraints);
|
||||
|
|
|
|||
|
|
@ -640,7 +640,7 @@ impl<'tcx> LivenessContext<'_, '_, 'tcx> {
|
|||
|
||||
let op = typeck.infcx.param_env.and(DropckOutlives { dropped_ty });
|
||||
|
||||
match op.fully_perform(typeck.infcx, DUMMY_SP) {
|
||||
match op.fully_perform(typeck.infcx, typeck.root_cx.root_def_id(), DUMMY_SP) {
|
||||
Ok(TypeOpOutput { output, constraints, .. }) => {
|
||||
DropData { dropck_result: output, region_constraint_data: constraints }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ pub(crate) fn type_check<'tcx>(
|
|||
region_bound_pairs,
|
||||
normalized_inputs_and_output,
|
||||
known_type_outlives_obligations,
|
||||
} = free_region_relations::create(infcx, infcx.param_env, universal_regions, &mut constraints);
|
||||
} = free_region_relations::create(infcx, universal_regions, &mut constraints);
|
||||
|
||||
let pre_obligations = infcx.take_registered_region_obligations();
|
||||
assert!(
|
||||
|
|
@ -408,7 +408,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
self.infcx,
|
||||
self.universal_regions,
|
||||
self.region_bound_pairs,
|
||||
self.infcx.param_env,
|
||||
self.known_type_outlives_obligations,
|
||||
locations,
|
||||
locations.span(self.body),
|
||||
|
|
@ -2458,12 +2457,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
args: GenericArgsRef<'tcx>,
|
||||
locations: Locations,
|
||||
) -> ty::InstantiatedPredicates<'tcx> {
|
||||
let root_def_id = self.root_cx.root_def_id();
|
||||
if let Some(closure_requirements) = &self.root_cx.closure_requirements(def_id) {
|
||||
constraint_conversion::ConstraintConversion::new(
|
||||
self.infcx,
|
||||
self.universal_regions,
|
||||
self.region_bound_pairs,
|
||||
self.infcx.param_env,
|
||||
self.known_type_outlives_obligations,
|
||||
locations,
|
||||
self.body.span, // irrelevant; will be overridden.
|
||||
|
|
@ -2473,9 +2472,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
.apply_closure_requirements(closure_requirements, def_id, args);
|
||||
}
|
||||
|
||||
// Now equate closure args to regions inherited from `typeck_root_def_id`. Fixes #98589.
|
||||
let typeck_root_def_id = tcx.typeck_root_def_id(self.body.source.def_id());
|
||||
let typeck_root_args = ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id);
|
||||
// Now equate closure args to regions inherited from `root_def_id`. Fixes #98589.
|
||||
let typeck_root_args = ty::GenericArgs::identity_for_item(tcx, root_def_id);
|
||||
|
||||
let parent_args = match tcx.def_kind(def_id) {
|
||||
// We don't want to dispatch on 3 different kind of closures here, so take
|
||||
|
|
@ -2550,17 +2548,14 @@ impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> {
|
|||
fn fully_perform(
|
||||
mut self,
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
root_def_id: LocalDefId,
|
||||
span: Span,
|
||||
) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed> {
|
||||
let (mut output, region_constraints) = scrape_region_constraints(
|
||||
infcx,
|
||||
|ocx| {
|
||||
let (mut output, region_constraints) =
|
||||
scrape_region_constraints(infcx, root_def_id, "InstantiateOpaqueType", span, |ocx| {
|
||||
ocx.register_obligations(self.obligations.clone());
|
||||
Ok(())
|
||||
},
|
||||
"InstantiateOpaqueType",
|
||||
span,
|
||||
)?;
|
||||
})?;
|
||||
self.region_constraints = Some(region_constraints);
|
||||
output.error_info = Some(self);
|
||||
Ok(output)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
//! Implementation of the `#[cfg_accessible(path)]` attribute macro.
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_attr_parsing::validate_attr;
|
||||
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier};
|
||||
use rustc_feature::AttributeTemplate;
|
||||
use rustc_parse::validate_attr;
|
||||
use rustc_span::{Span, sym};
|
||||
|
||||
use crate::errors;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use rustc_ast as ast;
|
||||
use rustc_ast::{GenericParamKind, ItemKind, MetaItemInner, MetaItemKind, StmtKind};
|
||||
use rustc_attr_parsing::validate_attr;
|
||||
use rustc_expand::base::{
|
||||
Annotatable, DeriveResolution, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier,
|
||||
};
|
||||
use rustc_feature::AttributeTemplate;
|
||||
use rustc_parse::validate_attr;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::{ErrorGuaranteed, Ident, Span, sym};
|
||||
|
||||
|
|
|
|||
|
|
@ -10,11 +10,12 @@ use rustc_ast::{
|
|||
};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans, listify, pluralize,
|
||||
Applicability, BufferedEarlyLint, Diag, MultiSpan, PResult, SingleLabelManySpans, listify,
|
||||
pluralize,
|
||||
};
|
||||
use rustc_expand::base::*;
|
||||
use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
|
||||
use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiag, LintId};
|
||||
use rustc_lint_defs::{BuiltinLintDiag, LintId};
|
||||
use rustc_parse::exp;
|
||||
use rustc_parse_format as parse;
|
||||
use rustc_span::{BytePos, ErrorGuaranteed, Ident, InnerSpan, Span, Symbol};
|
||||
|
|
@ -595,7 +596,8 @@ fn make_format_args(
|
|||
named_arg_sp: arg_name.span,
|
||||
named_arg_name: arg_name.name.to_string(),
|
||||
is_formatting_arg: matches!(used_as, Width | Precision),
|
||||
},
|
||||
}
|
||||
.into(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{self as ast, AttrStyle, Attribute, MetaItem, attr, token};
|
||||
use rustc_attr_parsing::validate_attr;
|
||||
use rustc_errors::{Applicability, Diag, ErrorGuaranteed};
|
||||
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt};
|
||||
use rustc_expand::expand::AstFragment;
|
||||
use rustc_feature::AttributeTemplate;
|
||||
use rustc_lint_defs::BuiltinLintDiag;
|
||||
use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES;
|
||||
use rustc_parse::{exp, parser, validate_attr};
|
||||
use rustc_parse::{exp, parser};
|
||||
use rustc_session::errors::report_lit_error;
|
||||
use rustc_span::{BytePos, Span, Symbol};
|
||||
|
||||
|
|
|
|||
|
|
@ -171,9 +171,6 @@ codegen_ssa_invalid_monomorphization_unsupported_symbol = invalid monomorphizati
|
|||
|
||||
codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size = invalid monomorphization of `{$name}` intrinsic: unsupported {$symbol} from `{$in_ty}` with element `{$in_elem}` of size `{$size}` to `{$ret_ty}`
|
||||
|
||||
codegen_ssa_invalid_sanitize = invalid argument for `sanitize`
|
||||
.note = expected one of: `address`, `kernel_address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow_call_stack`, or `thread`
|
||||
|
||||
codegen_ssa_invalid_windows_subsystem = invalid windows subsystem `{$subsystem}`, only `windows` and `console` are allowed
|
||||
|
||||
codegen_ssa_ld64_unimplemented_modifier = `as-needed` modifier not implemented yet for ld64
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ fn process_builtin_attrs(
|
|||
}
|
||||
}
|
||||
AttributeKind::Optimize(optimize, _) => codegen_fn_attrs.optimize = *optimize,
|
||||
AttributeKind::TargetFeature(features, attr_span) => {
|
||||
AttributeKind::TargetFeature { features, attr_span, was_forced } => {
|
||||
let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else {
|
||||
tcx.dcx().span_delayed_bug(*attr_span, "target_feature applied to non-fn");
|
||||
continue;
|
||||
|
|
@ -201,7 +201,7 @@ fn process_builtin_attrs(
|
|||
let safe_target_features =
|
||||
matches!(sig.header.safety, hir::HeaderSafety::SafeTargetFeatures);
|
||||
codegen_fn_attrs.safe_target_features = safe_target_features;
|
||||
if safe_target_features {
|
||||
if safe_target_features && !was_forced {
|
||||
if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
|
||||
// The `#[target_feature]` attribute is allowed on
|
||||
// WebAssembly targets on all functions. Prior to stabilizing
|
||||
|
|
@ -232,6 +232,7 @@ fn process_builtin_attrs(
|
|||
tcx,
|
||||
did,
|
||||
features,
|
||||
*was_forced,
|
||||
rust_target_features,
|
||||
&mut codegen_fn_attrs.target_features,
|
||||
);
|
||||
|
|
@ -292,6 +293,9 @@ fn process_builtin_attrs(
|
|||
codegen_fn_attrs.linkage = linkage;
|
||||
}
|
||||
}
|
||||
AttributeKind::Sanitize { span, .. } => {
|
||||
interesting_spans.sanitize = Some(*span);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -309,7 +313,6 @@ fn process_builtin_attrs(
|
|||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED
|
||||
}
|
||||
sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL,
|
||||
sym::sanitize => interesting_spans.sanitize = Some(attr.span()),
|
||||
sym::instruction_set => {
|
||||
codegen_fn_attrs.instruction_set = parse_instruction_set_attr(tcx, attr)
|
||||
}
|
||||
|
|
@ -462,7 +465,7 @@ fn check_result(
|
|||
.collect(),
|
||||
) {
|
||||
let span =
|
||||
find_attr!(tcx.get_all_attrs(did), AttributeKind::TargetFeature(_, span) => *span)
|
||||
find_attr!(tcx.get_all_attrs(did), AttributeKind::TargetFeature{attr_span: span, ..} => *span)
|
||||
.unwrap_or_else(|| tcx.def_span(did));
|
||||
|
||||
tcx.dcx()
|
||||
|
|
@ -559,79 +562,9 @@ fn opt_trait_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
|
|||
}
|
||||
}
|
||||
|
||||
/// For an attr that has the `sanitize` attribute, read the list of
|
||||
/// disabled sanitizers. `current_attr` holds the information about
|
||||
/// previously parsed attributes.
|
||||
fn parse_sanitize_attr(
|
||||
tcx: TyCtxt<'_>,
|
||||
attr: &Attribute,
|
||||
current_attr: SanitizerSet,
|
||||
) -> SanitizerSet {
|
||||
let mut result = current_attr;
|
||||
if let Some(list) = attr.meta_item_list() {
|
||||
for item in list.iter() {
|
||||
let MetaItemInner::MetaItem(set) = item else {
|
||||
tcx.dcx().emit_err(errors::InvalidSanitize { span: attr.span() });
|
||||
break;
|
||||
};
|
||||
let segments = set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
|
||||
match segments.as_slice() {
|
||||
// Similar to clang, sanitize(address = ..) and
|
||||
// sanitize(kernel_address = ..) control both ASan and KASan
|
||||
// Source: https://reviews.llvm.org/D44981.
|
||||
[sym::address] | [sym::kernel_address] if set.value_str() == Some(sym::off) => {
|
||||
result |= SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS
|
||||
}
|
||||
[sym::address] | [sym::kernel_address] if set.value_str() == Some(sym::on) => {
|
||||
result &= !SanitizerSet::ADDRESS;
|
||||
result &= !SanitizerSet::KERNELADDRESS;
|
||||
}
|
||||
[sym::cfi] if set.value_str() == Some(sym::off) => result |= SanitizerSet::CFI,
|
||||
[sym::cfi] if set.value_str() == Some(sym::on) => result &= !SanitizerSet::CFI,
|
||||
[sym::kcfi] if set.value_str() == Some(sym::off) => result |= SanitizerSet::KCFI,
|
||||
[sym::kcfi] if set.value_str() == Some(sym::on) => result &= !SanitizerSet::KCFI,
|
||||
[sym::memory] if set.value_str() == Some(sym::off) => {
|
||||
result |= SanitizerSet::MEMORY
|
||||
}
|
||||
[sym::memory] if set.value_str() == Some(sym::on) => {
|
||||
result &= !SanitizerSet::MEMORY
|
||||
}
|
||||
[sym::memtag] if set.value_str() == Some(sym::off) => {
|
||||
result |= SanitizerSet::MEMTAG
|
||||
}
|
||||
[sym::memtag] if set.value_str() == Some(sym::on) => {
|
||||
result &= !SanitizerSet::MEMTAG
|
||||
}
|
||||
[sym::shadow_call_stack] if set.value_str() == Some(sym::off) => {
|
||||
result |= SanitizerSet::SHADOWCALLSTACK
|
||||
}
|
||||
[sym::shadow_call_stack] if set.value_str() == Some(sym::on) => {
|
||||
result &= !SanitizerSet::SHADOWCALLSTACK
|
||||
}
|
||||
[sym::thread] if set.value_str() == Some(sym::off) => {
|
||||
result |= SanitizerSet::THREAD
|
||||
}
|
||||
[sym::thread] if set.value_str() == Some(sym::on) => {
|
||||
result &= !SanitizerSet::THREAD
|
||||
}
|
||||
[sym::hwaddress] if set.value_str() == Some(sym::off) => {
|
||||
result |= SanitizerSet::HWADDRESS
|
||||
}
|
||||
[sym::hwaddress] if set.value_str() == Some(sym::on) => {
|
||||
result &= !SanitizerSet::HWADDRESS
|
||||
}
|
||||
_ => {
|
||||
tcx.dcx().emit_err(errors::InvalidSanitize { span: attr.span() });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn disabled_sanitizers_for(tcx: TyCtxt<'_>, did: LocalDefId) -> SanitizerSet {
|
||||
// Backtrack to the crate root.
|
||||
let disabled = match tcx.opt_local_parent(did) {
|
||||
let mut disabled = match tcx.opt_local_parent(did) {
|
||||
// Check the parent (recursively).
|
||||
Some(parent) => tcx.disabled_sanitizers_for(parent),
|
||||
// We reached the crate root without seeing an attribute, so
|
||||
|
|
@ -640,8 +573,17 @@ fn disabled_sanitizers_for(tcx: TyCtxt<'_>, did: LocalDefId) -> SanitizerSet {
|
|||
};
|
||||
|
||||
// Check for a sanitize annotation directly on this def.
|
||||
if let Some(attr) = tcx.get_attr(did, sym::sanitize) {
|
||||
return parse_sanitize_attr(tcx, attr, disabled);
|
||||
if let Some((on_set, off_set)) = find_attr!(tcx.get_all_attrs(did), AttributeKind::Sanitize {on_set, off_set, ..} => (on_set, off_set))
|
||||
{
|
||||
// the on set is the set of sanitizers explicitly enabled.
|
||||
// we mask those out since we want the set of disabled sanitizers here
|
||||
disabled &= !*on_set;
|
||||
// the off set is the set of sanitizers explicitly disabled.
|
||||
// we or those in here.
|
||||
disabled |= *off_set;
|
||||
// the on set and off set are distjoint since there's a third option: unset.
|
||||
// a node may not set the sanitizer setting in which case it inherits from parents.
|
||||
// the code above in this function does this backtracking
|
||||
}
|
||||
disabled
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1120,14 +1120,6 @@ impl IntoDiagArg for ExpectedPointerMutability {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_invalid_sanitize)]
|
||||
#[note]
|
||||
pub(crate) struct InvalidSanitize {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_target_feature_safe_trait)]
|
||||
pub(crate) struct TargetFeatureSafeTrait {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet};
|
|||
use rustc_hir::attrs::InstructionSetAttr;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
|
||||
use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
|
||||
use rustc_middle::middle::codegen_fn_attrs::{TargetFeature, TargetFeatureKind};
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Session;
|
||||
|
|
@ -22,6 +22,7 @@ pub(crate) fn from_target_feature_attr(
|
|||
tcx: TyCtxt<'_>,
|
||||
did: LocalDefId,
|
||||
features: &[(Symbol, Span)],
|
||||
was_forced: bool,
|
||||
rust_target_features: &UnordMap<String, target_features::Stability>,
|
||||
target_features: &mut Vec<TargetFeature>,
|
||||
) {
|
||||
|
|
@ -88,7 +89,14 @@ pub(crate) fn from_target_feature_attr(
|
|||
}
|
||||
}
|
||||
}
|
||||
target_features.push(TargetFeature { name, implied: name != feature })
|
||||
let kind = if name != feature {
|
||||
TargetFeatureKind::Implied
|
||||
} else if was_forced {
|
||||
TargetFeatureKind::Forced
|
||||
} else {
|
||||
TargetFeatureKind::Enabled
|
||||
};
|
||||
target_features.push(TargetFeature { name, kind })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
//!
|
||||
//! The main entry point is the `step` method.
|
||||
|
||||
use std::iter;
|
||||
|
||||
use either::Either;
|
||||
use rustc_abi::{FIRST_VARIANT, FieldIdx};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
|
@ -426,6 +428,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
terminator: &mir::Terminator<'tcx>,
|
||||
func: &mir::Operand<'tcx>,
|
||||
args: &[Spanned<mir::Operand<'tcx>>],
|
||||
dest: &mir::Place<'tcx>,
|
||||
) -> InterpResult<'tcx, EvaluatedCalleeAndArgs<'tcx, M>> {
|
||||
let func = self.eval_operand(func, None)?;
|
||||
|
||||
|
|
@ -435,14 +438,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
// protection, but then we'd force *a lot* of arguments into memory. So we do some syntactic
|
||||
// pre-processing here where if all `move` arguments are syntactically distinct local
|
||||
// variables (and none is indirect), we can skip the in-memory forcing.
|
||||
// We have to include `dest` in that list so that we can detect aliasing of an in-place
|
||||
// argument with the return place.
|
||||
let move_definitely_disjoint = 'move_definitely_disjoint: {
|
||||
let mut previous_locals = FxHashSet::<mir::Local>::default();
|
||||
for arg in args {
|
||||
let mir::Operand::Move(place) = arg.node else {
|
||||
continue; // we can skip non-`Move` arguments.
|
||||
};
|
||||
for place in args
|
||||
.iter()
|
||||
.filter_map(|a| {
|
||||
// We only have to care about `Move` arguments.
|
||||
if let mir::Operand::Move(place) = &a.node { Some(place) } else { None }
|
||||
})
|
||||
.chain(iter::once(dest))
|
||||
{
|
||||
if place.is_indirect_first_projection() {
|
||||
// An indirect `Move` argument could alias with anything else...
|
||||
// An indirect in-place argument could alias with anything else...
|
||||
break 'move_definitely_disjoint false;
|
||||
}
|
||||
if !previous_locals.insert(place.local) {
|
||||
|
|
@ -544,7 +553,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
let old_loc = self.frame().loc;
|
||||
|
||||
let EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location } =
|
||||
self.eval_callee_and_args(terminator, func, args)?;
|
||||
self.eval_callee_and_args(terminator, func, args, &destination)?;
|
||||
|
||||
let destination = self.eval_place(destination)?;
|
||||
self.init_fn_call(
|
||||
|
|
@ -567,7 +576,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
let old_frame_idx = self.frame_idx();
|
||||
|
||||
let EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location } =
|
||||
self.eval_callee_and_args(terminator, func, args)?;
|
||||
self.eval_callee_and_args(terminator, func, args, &mir::Place::return_place())?;
|
||||
|
||||
self.init_fn_tail_call(callee, (fn_sig.abi, fn_abi), &args, with_caller_location)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ pub mod thinvec;
|
|||
pub mod thousands;
|
||||
pub mod transitive_relation;
|
||||
pub mod unhash;
|
||||
pub mod union_find;
|
||||
pub mod unord;
|
||||
pub mod vec_cache;
|
||||
pub mod work_queue;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ mod tests;
|
|||
/// Simple implementation of a union-find data structure, i.e. a disjoint-set
|
||||
/// forest.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct UnionFind<Key: Idx> {
|
||||
pub struct UnionFind<Key: Idx> {
|
||||
table: IndexVec<Key, UnionFindEntry<Key>>,
|
||||
}
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ struct UnionFindEntry<Key> {
|
|||
impl<Key: Idx> UnionFind<Key> {
|
||||
/// Creates a new disjoint-set forest containing the keys `0..num_keys`.
|
||||
/// Initially, every key is part of its own one-element set.
|
||||
pub(crate) fn new(num_keys: usize) -> Self {
|
||||
pub fn new(num_keys: usize) -> Self {
|
||||
// Initially, every key is the root of its own set, so its parent is itself.
|
||||
Self { table: IndexVec::from_fn_n(|key| UnionFindEntry { parent: key, rank: 0 }, num_keys) }
|
||||
}
|
||||
|
|
@ -38,7 +38,7 @@ impl<Key: Idx> UnionFind<Key> {
|
|||
///
|
||||
/// Also updates internal data structures to make subsequent `find`
|
||||
/// operations faster.
|
||||
pub(crate) fn find(&mut self, key: Key) -> Key {
|
||||
pub fn find(&mut self, key: Key) -> Key {
|
||||
// Loop until we find a key that is its own parent.
|
||||
let mut curr = key;
|
||||
while let parent = self.table[curr].parent
|
||||
|
|
@ -60,7 +60,7 @@ impl<Key: Idx> UnionFind<Key> {
|
|||
/// Merges the set containing `a` and the set containing `b` into one set.
|
||||
///
|
||||
/// Returns the common root of both keys, after the merge.
|
||||
pub(crate) fn unify(&mut self, a: Key, b: Key) -> Key {
|
||||
pub fn unify(&mut self, a: Key, b: Key) -> Key {
|
||||
let mut a = self.find(a);
|
||||
let mut b = self.find(b);
|
||||
|
||||
|
|
@ -90,7 +90,7 @@ impl<Key: Idx> UnionFind<Key> {
|
|||
|
||||
/// Takes a "snapshot" of the current state of this disjoint-set forest, in
|
||||
/// the form of a vector that directly maps each key to its current root.
|
||||
pub(crate) fn snapshot(&mut self) -> IndexVec<Key, Key> {
|
||||
pub fn snapshot(&mut self) -> IndexVec<Key, Key> {
|
||||
self.table.indices().map(|key| self.find(key)).collect()
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ edition = "2024"
|
|||
annotate-snippets = "0.11"
|
||||
derive_setters = "0.1.6"
|
||||
rustc_abi = { path = "../rustc_abi" }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_error_codes = { path = "../rustc_error_codes" }
|
||||
rustc_error_messages = { path = "../rustc_error_messages" }
|
||||
|
|
|
|||
85
compiler/rustc_errors/src/decorate_diag.rs
Normal file
85
compiler/rustc_errors/src/decorate_diag.rs
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/// This module provides types and traits for buffering lints until later in compilation.
|
||||
use rustc_ast::node_id::NodeId;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_error_messages::MultiSpan;
|
||||
use rustc_lint_defs::{BuiltinLintDiag, Lint, LintId};
|
||||
|
||||
use crate::{DynSend, LintDiagnostic, LintDiagnosticBox};
|
||||
|
||||
/// We can't implement `LintDiagnostic` for `BuiltinLintDiag`, because decorating some of its
|
||||
/// variants requires types we don't have yet. So, handle that case separately.
|
||||
pub enum DecorateDiagCompat {
|
||||
Dynamic(Box<dyn for<'a> LintDiagnosticBox<'a, ()> + DynSend + 'static>),
|
||||
Builtin(BuiltinLintDiag),
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for DecorateDiagCompat {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("DecorateDiagCompat").finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl !LintDiagnostic<'_, ()> for BuiltinLintDiag {}
|
||||
|
||||
impl<D: for<'a> LintDiagnostic<'a, ()> + DynSend + 'static> From<D> for DecorateDiagCompat {
|
||||
#[inline]
|
||||
fn from(d: D) -> Self {
|
||||
Self::Dynamic(Box::new(d))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BuiltinLintDiag> for DecorateDiagCompat {
|
||||
#[inline]
|
||||
fn from(b: BuiltinLintDiag) -> Self {
|
||||
Self::Builtin(b)
|
||||
}
|
||||
}
|
||||
|
||||
/// Lints that are buffered up early on in the `Session` before the
|
||||
/// `LintLevels` is calculated.
|
||||
#[derive(Debug)]
|
||||
pub struct BufferedEarlyLint {
|
||||
/// The span of code that we are linting on.
|
||||
pub span: Option<MultiSpan>,
|
||||
|
||||
/// The `NodeId` of the AST node that generated the lint.
|
||||
pub node_id: NodeId,
|
||||
|
||||
/// A lint Id that can be passed to
|
||||
/// `rustc_lint::early::EarlyContextAndPass::check_id`.
|
||||
pub lint_id: LintId,
|
||||
|
||||
/// Customization of the `Diag<'_>` for the lint.
|
||||
pub diagnostic: DecorateDiagCompat,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct LintBuffer {
|
||||
pub map: FxIndexMap<NodeId, Vec<BufferedEarlyLint>>,
|
||||
}
|
||||
|
||||
impl LintBuffer {
|
||||
pub fn add_early_lint(&mut self, early_lint: BufferedEarlyLint) {
|
||||
self.map.entry(early_lint.node_id).or_default().push(early_lint);
|
||||
}
|
||||
|
||||
pub fn take(&mut self, id: NodeId) -> Vec<BufferedEarlyLint> {
|
||||
// FIXME(#120456) - is `swap_remove` correct?
|
||||
self.map.swap_remove(&id).unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn buffer_lint(
|
||||
&mut self,
|
||||
lint: &'static Lint,
|
||||
node_id: NodeId,
|
||||
span: impl Into<MultiSpan>,
|
||||
decorate: impl Into<DecorateDiagCompat>,
|
||||
) {
|
||||
self.add_early_lint(BufferedEarlyLint {
|
||||
lint_id: LintId::of(lint),
|
||||
node_id,
|
||||
span: Some(span.into()),
|
||||
diagnostic: decorate.into(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -138,10 +138,20 @@ where
|
|||
/// `#[derive(LintDiagnostic)]` -- see [rustc_macros::LintDiagnostic].
|
||||
#[rustc_diagnostic_item = "LintDiagnostic"]
|
||||
pub trait LintDiagnostic<'a, G: EmissionGuarantee> {
|
||||
/// Decorate and emit a lint.
|
||||
/// Decorate a lint with the information from this type.
|
||||
fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>);
|
||||
}
|
||||
|
||||
pub trait LintDiagnosticBox<'a, G: EmissionGuarantee> {
|
||||
fn decorate_lint_box<'b>(self: Box<Self>, diag: &'b mut Diag<'a, G>);
|
||||
}
|
||||
|
||||
impl<'a, G: EmissionGuarantee, D: LintDiagnostic<'a, G>> LintDiagnosticBox<'a, G> for D {
|
||||
fn decorate_lint_box<'b>(self: Box<Self>, diag: &'b mut Diag<'a, G>) {
|
||||
self.decorate_lint(diag);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Encodable, Decodable)]
|
||||
pub(crate) struct DiagLocation {
|
||||
file: Cow<'static, str>,
|
||||
|
|
|
|||
|
|
@ -40,9 +40,10 @@ use std::{fmt, panic};
|
|||
|
||||
use Level::*;
|
||||
pub use codes::*;
|
||||
pub use decorate_diag::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer};
|
||||
pub use diagnostic::{
|
||||
BugAbort, Diag, DiagArgMap, DiagInner, DiagStyledString, Diagnostic, EmissionGuarantee,
|
||||
FatalAbort, LintDiagnostic, StringPart, Subdiag, Subdiagnostic,
|
||||
FatalAbort, LintDiagnostic, LintDiagnosticBox, StringPart, Subdiag, Subdiagnostic,
|
||||
};
|
||||
pub use diagnostic_impls::{
|
||||
DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter,
|
||||
|
|
@ -80,6 +81,7 @@ use crate::timings::TimingRecord;
|
|||
|
||||
pub mod annotate_snippet_emitter_writer;
|
||||
pub mod codes;
|
||||
mod decorate_diag;
|
||||
mod diagnostic;
|
||||
mod diagnostic_impls;
|
||||
pub mod emitter;
|
||||
|
|
|
|||
|
|
@ -13,13 +13,13 @@ use rustc_ast::visit::{AssocCtxt, Visitor};
|
|||
use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
use rustc_data_structures::sync;
|
||||
use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult};
|
||||
use rustc_errors::{BufferedEarlyLint, DiagCtxtHandle, ErrorGuaranteed, PResult};
|
||||
use rustc_feature::Features;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::attrs::{AttributeKind, CfgEntry, Deprecation};
|
||||
use rustc_hir::def::MacroKinds;
|
||||
use rustc_hir::{Stability, find_attr};
|
||||
use rustc_lint_defs::{BufferedEarlyLint, RegisteredTools};
|
||||
use rustc_lint_defs::RegisteredTools;
|
||||
use rustc_parse::MACRO_ARGUMENTS;
|
||||
use rustc_parse::parser::{ForceCollect, Parser};
|
||||
use rustc_session::config::CollapseMacroDebuginfo;
|
||||
|
|
|
|||
|
|
@ -11,8 +11,10 @@ use rustc_ast::{
|
|||
NodeId, NormalAttr,
|
||||
};
|
||||
use rustc_attr_parsing as attr;
|
||||
use rustc_attr_parsing::validate_attr::deny_builtin_meta_unsafety;
|
||||
use rustc_attr_parsing::{
|
||||
AttributeParser, CFG_TEMPLATE, EvalConfigResult, ShouldEmit, eval_config_entry, parse_cfg_attr,
|
||||
validate_attr,
|
||||
};
|
||||
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
|
||||
use rustc_feature::{
|
||||
|
|
@ -20,8 +22,6 @@ use rustc_feature::{
|
|||
REMOVED_LANG_FEATURES, UNSTABLE_LANG_FEATURES,
|
||||
};
|
||||
use rustc_lint_defs::BuiltinLintDiag;
|
||||
use rustc_parse::validate_attr;
|
||||
use rustc_parse::validate_attr::deny_builtin_meta_unsafety;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::{STDLIB_STABLE_CRATES, Span, Symbol, sym};
|
||||
|
|
@ -415,16 +415,6 @@ impl<'a> StripUnconfigured<'a> {
|
|||
node: NodeId,
|
||||
emit_errors: ShouldEmit,
|
||||
) -> EvalConfigResult {
|
||||
// We need to run this to do basic validation of the attribute, such as that lits are valid, etc
|
||||
// FIXME(jdonszelmann) this should not be necessary in the future
|
||||
match validate_attr::parse_meta(&self.sess.psess, attr) {
|
||||
Ok(_) => {}
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
return EvalConfigResult::True;
|
||||
}
|
||||
}
|
||||
|
||||
// Unsafety check needs to be done explicitly here because this attribute will be removed before the normal check
|
||||
deny_builtin_meta_unsafety(
|
||||
self.sess.dcx(),
|
||||
|
|
|
|||
|
|
@ -1,27 +1,28 @@
|
|||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::{iter, mem};
|
||||
use std::{iter, mem, slice};
|
||||
|
||||
use rustc_ast::mut_visit::*;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::visit::{self, AssocCtxt, Visitor, VisitorResult, try_visit, walk_list};
|
||||
use rustc_ast::{
|
||||
self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, DUMMY_NODE_ID,
|
||||
ExprKind, ForeignItemKind, HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemInner,
|
||||
MetaItemKind, ModKind, NodeId, PatKind, StmtKind, TyKind, token,
|
||||
self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, CRATE_NODE_ID,
|
||||
DUMMY_NODE_ID, ExprKind, ForeignItemKind, HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle,
|
||||
MetaItemInner, MetaItemKind, ModKind, NodeId, PatKind, StmtKind, TyKind, token,
|
||||
};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_attr_parsing::{EvalConfigResult, ShouldEmit};
|
||||
use rustc_attr_parsing::{AttributeParser, EvalConfigResult, ShouldEmit, validate_attr};
|
||||
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_errors::PResult;
|
||||
use rustc_feature::Features;
|
||||
use rustc_hir::Target;
|
||||
use rustc_hir::def::MacroKinds;
|
||||
use rustc_parse::parser::{
|
||||
AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser, RecoverColon, RecoverComma,
|
||||
token_descr,
|
||||
};
|
||||
use rustc_parse::validate_attr;
|
||||
use rustc_session::lint::BuiltinLintDiag;
|
||||
use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS};
|
||||
use rustc_session::parse::feature_err;
|
||||
|
|
@ -2158,6 +2159,16 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||
attr,
|
||||
self.cx.current_expansion.lint_node_id,
|
||||
);
|
||||
AttributeParser::parse_limited_all(
|
||||
self.cx.sess,
|
||||
slice::from_ref(attr),
|
||||
None,
|
||||
Target::MacroCall,
|
||||
call.span(),
|
||||
CRATE_NODE_ID,
|
||||
Some(self.cx.ecfg.features),
|
||||
ShouldEmit::ErrorsAndLints,
|
||||
);
|
||||
|
||||
let current_span = if let Some(sp) = span { sp.to(attr.span) } else { attr.span };
|
||||
span = Some(current_span);
|
||||
|
|
@ -2469,7 +2480,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
|
|||
if let Some(attr) = node.attrs.first() {
|
||||
self.cfg().maybe_emit_expr_attr_err(attr);
|
||||
}
|
||||
self.visit_node(node)
|
||||
ensure_sufficient_stack(|| self.visit_node(node))
|
||||
}
|
||||
|
||||
fn visit_method_receiver_expr(&mut self, node: &mut ast::Expr) {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@ use std::iter::once;
|
|||
use std::path::{self, Path, PathBuf};
|
||||
|
||||
use rustc_ast::{AttrVec, Attribute, Inline, Item, ModSpans};
|
||||
use rustc_attr_parsing::validate_attr;
|
||||
use rustc_errors::{Diag, ErrorGuaranteed};
|
||||
use rustc_parse::{exp, new_parser_from_file, unwrap_or_emit_fatal, validate_attr};
|
||||
use rustc_parse::{exp, new_parser_from_file, unwrap_or_emit_fatal};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::{Ident, Span, sym};
|
||||
|
|
|
|||
|
|
@ -250,12 +250,14 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
|
|||
Question => op("?"),
|
||||
SingleQuote => op("'"),
|
||||
|
||||
Ident(sym, is_raw) => {
|
||||
trees.push(TokenTree::Ident(Ident { sym, is_raw: is_raw.into(), span }))
|
||||
}
|
||||
Ident(sym, is_raw) => trees.push(TokenTree::Ident(Ident {
|
||||
sym,
|
||||
is_raw: matches!(is_raw, IdentIsRaw::Yes),
|
||||
span,
|
||||
})),
|
||||
NtIdent(ident, is_raw) => trees.push(TokenTree::Ident(Ident {
|
||||
sym: ident.name,
|
||||
is_raw: is_raw.into(),
|
||||
is_raw: matches!(is_raw, IdentIsRaw::Yes),
|
||||
span: ident.span,
|
||||
})),
|
||||
|
||||
|
|
@ -263,7 +265,11 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
|
|||
let ident = rustc_span::Ident::new(name, span).without_first_quote();
|
||||
trees.extend([
|
||||
TokenTree::Punct(Punct { ch: b'\'', joint: true, span }),
|
||||
TokenTree::Ident(Ident { sym: ident.name, is_raw: is_raw.into(), span }),
|
||||
TokenTree::Ident(Ident {
|
||||
sym: ident.name,
|
||||
is_raw: matches!(is_raw, IdentIsRaw::Yes),
|
||||
span,
|
||||
}),
|
||||
]);
|
||||
}
|
||||
NtLifetime(ident, is_raw) => {
|
||||
|
|
|
|||
|
|
@ -744,6 +744,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
template!(List: &["set"], "https://doc.rust-lang.org/reference/attributes/codegen.html#the-instruction_set-attribute"),
|
||||
ErrorPreceding, EncodeCrossCrate::No
|
||||
),
|
||||
gated!(
|
||||
unsafe force_target_feature, Normal, template!(List: &[r#"enable = "name""#]),
|
||||
DuplicatesOk, EncodeCrossCrate::No, effective_target_features, experimental!(force_target_feature)
|
||||
),
|
||||
gated!(
|
||||
sanitize, Normal, template!(List: &[r#"address = "on|off""#, r#"kernel_address = "on|off""#, r#"cfi = "on|off""#, r#"hwaddress = "on|off""#, r#"kcfi = "on|off""#, r#"memory = "on|off""#, r#"memtag = "on|off""#, r#"shadow_call_stack = "on|off""#, r#"thread = "on|off""#]), ErrorPreceding,
|
||||
EncodeCrossCrate::No, sanitize, experimental!(sanitize),
|
||||
|
|
|
|||
|
|
@ -480,6 +480,8 @@ declare_features! (
|
|||
(unstable, doc_cfg_hide, "1.57.0", Some(43781)),
|
||||
/// Allows `#[doc(masked)]`.
|
||||
(unstable, doc_masked, "1.21.0", Some(44027)),
|
||||
/// Allows features to allow target_feature to better interact with traits.
|
||||
(incomplete, effective_target_features, "CURRENT_RUSTC_VERSION", Some(143352)),
|
||||
/// Allows the .use postfix syntax `x.use` and use closures `use |x| { ... }`
|
||||
(incomplete, ergonomic_clones, "1.87.0", Some(132290)),
|
||||
/// Allows exhaustive pattern matching on types that contain uninhabited types.
|
||||
|
|
@ -614,6 +616,7 @@ declare_features! (
|
|||
(unstable, proc_macro_hygiene, "1.30.0", Some(54727)),
|
||||
/// Allows the use of raw-dylibs on ELF platforms
|
||||
(incomplete, raw_dylib_elf, "1.87.0", Some(135694)),
|
||||
(unstable, reborrow, "CURRENT_RUSTC_VERSION", Some(145612)),
|
||||
/// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024.
|
||||
(incomplete, ref_pat_eat_one_layer_2024, "1.79.0", Some(123076)),
|
||||
/// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024—structural variant
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute};
|
|||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::hygiene::Transparency;
|
||||
use rustc_span::{Ident, Span, Symbol};
|
||||
pub use rustc_target::spec::SanitizerSet;
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
use crate::attrs::pretty_printing::PrintAttribute;
|
||||
|
|
@ -505,6 +506,12 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_object_lifetime_default]`.
|
||||
RustcObjectLifetimeDefault,
|
||||
|
||||
/// Represents `#[sanitize]`
|
||||
///
|
||||
/// the on set and off set are distjoint since there's a third option: unset.
|
||||
/// a node may not set the sanitizer setting in which case it inherits from parents.
|
||||
Sanitize { on_set: SanitizerSet, off_set: SanitizerSet, span: Span },
|
||||
|
||||
/// Represents `#[should_panic]`
|
||||
ShouldPanic { reason: Option<Symbol>, span: Span },
|
||||
|
||||
|
|
@ -524,8 +531,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_std_internal_symbol]`.
|
||||
StdInternalSymbol(Span),
|
||||
|
||||
/// Represents `#[target_feature(enable = "...")]`
|
||||
TargetFeature(ThinVec<(Symbol, Span)>, Span),
|
||||
/// Represents `#[target_feature(enable = "...")]` and
|
||||
/// `#[unsafe(force_target_feature(enable = "...")]`.
|
||||
TargetFeature { features: ThinVec<(Symbol, Span)>, attr_span: Span, was_forced: bool },
|
||||
|
||||
/// Represents `#[track_caller]`
|
||||
TrackCaller(Span),
|
||||
|
|
|
|||
|
|
@ -73,12 +73,13 @@ impl AttributeKind {
|
|||
RustcLayoutScalarValidRangeEnd(..) => Yes,
|
||||
RustcLayoutScalarValidRangeStart(..) => Yes,
|
||||
RustcObjectLifetimeDefault => No,
|
||||
Sanitize { .. } => No,
|
||||
ShouldPanic { .. } => No,
|
||||
SkipDuringMethodDispatch { .. } => No,
|
||||
SpecializationTrait(..) => No,
|
||||
Stability { .. } => Yes,
|
||||
StdInternalSymbol(..) => No,
|
||||
TargetFeature(..) => No,
|
||||
TargetFeature { .. } => No,
|
||||
TrackCaller(..) => Yes,
|
||||
TypeConst(..) => Yes,
|
||||
UnsafeSpecializationMarker(..) => No,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use rustc_ast::{AttrStyle, IntTy, UintTy};
|
|||
use rustc_ast_pretty::pp::Printer;
|
||||
use rustc_span::hygiene::Transparency;
|
||||
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol};
|
||||
use rustc_target::spec::SanitizerSet;
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
/// This trait is used to print attributes in `rustc_hir_pretty`.
|
||||
|
|
@ -146,4 +147,14 @@ macro_rules! print_tup {
|
|||
print_tup!(A B C D E F G H);
|
||||
print_skip!(Span, (), ErrorGuaranteed);
|
||||
print_disp!(u16, bool, NonZero<u32>);
|
||||
print_debug!(Symbol, Ident, UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency);
|
||||
print_debug!(
|
||||
Symbol,
|
||||
Ident,
|
||||
UintTy,
|
||||
IntTy,
|
||||
Align,
|
||||
AttrStyle,
|
||||
CommentKind,
|
||||
Transparency,
|
||||
SanitizerSet,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -437,6 +437,9 @@ language_item_table! {
|
|||
DefaultTrait1, sym::default_trait1, default_trait1_trait, Target::Trait, GenericRequirement::None;
|
||||
|
||||
ContractCheckEnsures, sym::contract_check_ensures, contract_check_ensures_fn, Target::Fn, GenericRequirement::None;
|
||||
|
||||
// Reborrowing related lang-items
|
||||
Reborrow, sym::reborrow, reborrow, Target::Trait, GenericRequirement::Exact(0);
|
||||
}
|
||||
|
||||
/// The requirement imposed on the generics of a lang item
|
||||
|
|
|
|||
|
|
@ -2053,3 +2053,29 @@ pub(super) fn check_coroutine_obligations(
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn check_potentially_region_dependent_goals<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
if !tcx.next_trait_solver_globally() {
|
||||
return Ok(());
|
||||
}
|
||||
let typeck_results = tcx.typeck(def_id);
|
||||
let param_env = tcx.param_env(def_id);
|
||||
|
||||
// We use `TypingMode::Borrowck` as we want to use the opaque types computed by HIR typeck.
|
||||
let typing_mode = TypingMode::borrowck(tcx, def_id);
|
||||
let infcx = tcx.infer_ctxt().ignoring_regions().build(typing_mode);
|
||||
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
|
||||
for (predicate, cause) in &typeck_results.potentially_region_dependent_goals {
|
||||
let predicate = fold_regions(tcx, *predicate, |_, _| {
|
||||
infcx.next_region_var(RegionVariableOrigin::Misc(cause.span))
|
||||
});
|
||||
ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate));
|
||||
}
|
||||
|
||||
let errors = ocx.select_all_or_error();
|
||||
debug!(?errors);
|
||||
if errors.is_empty() { Ok(()) } else { Err(infcx.err_ctxt().report_fulfillment_errors(errors)) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ pub(super) fn provide(providers: &mut Providers) {
|
|||
collect_return_position_impl_trait_in_trait_tys,
|
||||
compare_impl_item: compare_impl_item::compare_impl_item,
|
||||
check_coroutine_obligations: check::check_coroutine_obligations,
|
||||
check_potentially_region_dependent_goals: check::check_potentially_region_dependent_goals,
|
||||
check_type_wf: wfcheck::check_type_wf,
|
||||
check_well_formed: wfcheck::check_well_formed,
|
||||
..*providers
|
||||
|
|
|
|||
|
|
@ -83,14 +83,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
*self.deferred_cast_checks.borrow_mut() = deferred_cast_checks;
|
||||
}
|
||||
|
||||
pub(in super::super) fn check_transmutes(&self) {
|
||||
let mut deferred_transmute_checks = self.deferred_transmute_checks.borrow_mut();
|
||||
debug!("FnCtxt::check_transmutes: {} deferred checks", deferred_transmute_checks.len());
|
||||
for (from, to, hir_id) in deferred_transmute_checks.drain(..) {
|
||||
self.check_transmute(from, to, hir_id);
|
||||
}
|
||||
}
|
||||
|
||||
pub(in super::super) fn check_asms(&self) {
|
||||
let mut deferred_asm_checks = self.deferred_asm_checks.borrow_mut();
|
||||
debug!("FnCtxt::check_asm: {} deferred checks", deferred_asm_checks.len());
|
||||
|
|
|
|||
|
|
@ -7,11 +7,10 @@ use rustc_hir as hir;
|
|||
use rustc_index::Idx;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use tracing::trace;
|
||||
|
||||
use super::FnCtxt;
|
||||
|
||||
/// If the type is `Option<T>`, it will return `T`, otherwise
|
||||
/// the type itself. Works on most `Option`-like types.
|
||||
fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
|
|
@ -39,119 +38,117 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
|
|||
ty
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
/// FIXME: Move this check out of typeck, since it'll easily cycle when revealing opaques,
|
||||
/// and we shouldn't need to check anything here if the typeck results are tainted.
|
||||
pub(crate) fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) {
|
||||
let tcx = self.tcx;
|
||||
let dl = &tcx.data_layout;
|
||||
let span = tcx.hir_span(hir_id);
|
||||
let normalize = |ty| {
|
||||
let ty = self.resolve_vars_if_possible(ty);
|
||||
if let Ok(ty) =
|
||||
self.tcx.try_normalize_erasing_regions(self.typing_env(self.param_env), ty)
|
||||
{
|
||||
ty
|
||||
/// Try to display a sensible error with as much information as possible.
|
||||
fn skeleton_string<'tcx>(
|
||||
ty: Ty<'tcx>,
|
||||
sk: Result<SizeSkeleton<'tcx>, &'tcx LayoutError<'tcx>>,
|
||||
) -> String {
|
||||
match sk {
|
||||
Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"),
|
||||
Ok(SizeSkeleton::Known(size, _)) => {
|
||||
if let Some(v) = u128::from(size.bytes()).checked_mul(8) {
|
||||
format!("{v} bits")
|
||||
} else {
|
||||
Ty::new_error_with_message(
|
||||
tcx,
|
||||
span,
|
||||
"tried to normalize non-wf type in check_transmute",
|
||||
)
|
||||
// `u128` should definitely be able to hold the size of different architectures
|
||||
// larger sizes should be reported as error `are too big for the target architecture`
|
||||
// otherwise we have a bug somewhere
|
||||
bug!("{:?} overflow for u128", size)
|
||||
}
|
||||
};
|
||||
let from = normalize(from);
|
||||
let to = normalize(to);
|
||||
trace!(?from, ?to);
|
||||
if from.has_non_region_infer() || to.has_non_region_infer() {
|
||||
// Note: this path is currently not reached in any test, so any
|
||||
// example that triggers this would be worth minimizing and
|
||||
// converting into a test.
|
||||
self.dcx().span_bug(span, "argument to transmute has inference variables");
|
||||
}
|
||||
// Transmutes that are only changing lifetimes are always ok.
|
||||
if from == to {
|
||||
Ok(SizeSkeleton::Generic(size)) => {
|
||||
format!("generic size {size}")
|
||||
}
|
||||
Err(LayoutError::TooGeneric(bad)) => {
|
||||
if *bad == ty {
|
||||
"this type does not have a fixed size".to_owned()
|
||||
} else {
|
||||
format!("size can vary because of {bad}")
|
||||
}
|
||||
}
|
||||
Err(err) => err.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn check_transmute<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
typing_env: ty::TypingEnv<'tcx>,
|
||||
from: Ty<'tcx>,
|
||||
to: Ty<'tcx>,
|
||||
hir_id: HirId,
|
||||
) {
|
||||
let span = || tcx.hir_span(hir_id);
|
||||
let normalize = |ty| {
|
||||
if let Ok(ty) = tcx.try_normalize_erasing_regions(typing_env, ty) {
|
||||
ty
|
||||
} else {
|
||||
Ty::new_error_with_message(
|
||||
tcx,
|
||||
span(),
|
||||
format!("tried to normalize non-wf type {ty:#?} in check_transmute"),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let from = normalize(from);
|
||||
let to = normalize(to);
|
||||
trace!(?from, ?to);
|
||||
|
||||
// Transmutes that are only changing lifetimes are always ok.
|
||||
if from == to {
|
||||
return;
|
||||
}
|
||||
|
||||
let sk_from = SizeSkeleton::compute(from, tcx, typing_env);
|
||||
let sk_to = SizeSkeleton::compute(to, tcx, typing_env);
|
||||
trace!(?sk_from, ?sk_to);
|
||||
|
||||
// Check for same size using the skeletons.
|
||||
if let Ok(sk_from) = sk_from
|
||||
&& let Ok(sk_to) = sk_to
|
||||
{
|
||||
if sk_from.same_size(sk_to) {
|
||||
return;
|
||||
}
|
||||
|
||||
let skel = |ty| SizeSkeleton::compute(ty, tcx, self.typing_env(self.param_env));
|
||||
let sk_from = skel(from);
|
||||
let sk_to = skel(to);
|
||||
trace!(?sk_from, ?sk_to);
|
||||
|
||||
// Check for same size using the skeletons.
|
||||
if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) {
|
||||
if sk_from.same_size(sk_to) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Special-case transmuting from `typeof(function)` and
|
||||
// `Option<typeof(function)>` to present a clearer error.
|
||||
let from = unpack_option_like(tcx, from);
|
||||
if let (&ty::FnDef(..), SizeSkeleton::Known(size_to, _)) = (from.kind(), sk_to)
|
||||
&& size_to == Pointer(dl.instruction_address_space).size(&tcx)
|
||||
{
|
||||
struct_span_code_err!(self.dcx(), span, E0591, "can't transmute zero-sized type")
|
||||
.with_note(format!("source type: {from}"))
|
||||
.with_note(format!("target type: {to}"))
|
||||
.with_help("cast with `as` to a pointer instead")
|
||||
.emit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to display a sensible error with as much information as possible.
|
||||
let skeleton_string = |ty: Ty<'tcx>, sk: Result<_, &_>| match sk {
|
||||
Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"),
|
||||
Ok(SizeSkeleton::Known(size, _)) => {
|
||||
if let Some(v) = u128::from(size.bytes()).checked_mul(8) {
|
||||
format!("{v} bits")
|
||||
} else {
|
||||
// `u128` should definitely be able to hold the size of different architectures
|
||||
// larger sizes should be reported as error `are too big for the target architecture`
|
||||
// otherwise we have a bug somewhere
|
||||
bug!("{:?} overflow for u128", size)
|
||||
}
|
||||
}
|
||||
Ok(SizeSkeleton::Generic(size)) => {
|
||||
if let Some(size) =
|
||||
self.try_structurally_resolve_const(span, size).try_to_target_usize(tcx)
|
||||
{
|
||||
format!("{size} bytes")
|
||||
} else {
|
||||
format!("generic size {size}")
|
||||
}
|
||||
}
|
||||
Err(LayoutError::TooGeneric(bad)) => {
|
||||
if *bad == ty {
|
||||
"this type does not have a fixed size".to_owned()
|
||||
} else {
|
||||
format!("size can vary because of {bad}")
|
||||
}
|
||||
}
|
||||
Err(err) => err.to_string(),
|
||||
};
|
||||
|
||||
let mut err = struct_span_code_err!(
|
||||
self.dcx(),
|
||||
span,
|
||||
E0512,
|
||||
"cannot transmute between types of different sizes, \
|
||||
or dependently-sized types"
|
||||
);
|
||||
if from == to {
|
||||
err.note(format!("`{from}` does not have a fixed size"));
|
||||
err.emit();
|
||||
} else {
|
||||
err.note(format!("source type: `{}` ({})", from, skeleton_string(from, sk_from)))
|
||||
.note(format!("target type: `{}` ({})", to, skeleton_string(to, sk_to)));
|
||||
if let Err(LayoutError::ReferencesError(_)) = sk_from {
|
||||
err.delay_as_bug();
|
||||
} else if let Err(LayoutError::ReferencesError(_)) = sk_to {
|
||||
err.delay_as_bug();
|
||||
} else {
|
||||
err.emit();
|
||||
}
|
||||
// Special-case transmuting from `typeof(function)` and
|
||||
// `Option<typeof(function)>` to present a clearer error.
|
||||
let from = unpack_option_like(tcx, from);
|
||||
if let ty::FnDef(..) = from.kind()
|
||||
&& let SizeSkeleton::Known(size_to, _) = sk_to
|
||||
&& size_to == Pointer(tcx.data_layout.instruction_address_space).size(&tcx)
|
||||
{
|
||||
struct_span_code_err!(tcx.sess.dcx(), span(), E0591, "can't transmute zero-sized type")
|
||||
.with_note(format!("source type: {from}"))
|
||||
.with_note(format!("target type: {to}"))
|
||||
.with_help("cast with `as` to a pointer instead")
|
||||
.emit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let mut err = struct_span_code_err!(
|
||||
tcx.sess.dcx(),
|
||||
span(),
|
||||
E0512,
|
||||
"cannot transmute between types of different sizes, or dependently-sized types"
|
||||
);
|
||||
if from == to {
|
||||
err.note(format!("`{from}` does not have a fixed size"));
|
||||
err.emit();
|
||||
} else {
|
||||
err.note(format!("source type: `{}` ({})", from, skeleton_string(from, sk_from)));
|
||||
err.note(format!("target type: `{}` ({})", to, skeleton_string(to, sk_to)));
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn check_transmutes(tcx: TyCtxt<'_>, owner: LocalDefId) {
|
||||
assert!(!tcx.is_typeck_child(owner.to_def_id()));
|
||||
let typeck_results = tcx.typeck(owner);
|
||||
let None = typeck_results.tainted_by_errors else { return };
|
||||
|
||||
let typing_env = ty::TypingEnv::post_analysis(tcx, owner);
|
||||
for &(from, to, hir_id) in &typeck_results.transmutes_to_check {
|
||||
check_transmute(tcx, typing_env, from, to, hir_id);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ use rustc_hir_analysis::check::{check_abi, check_custom_abi};
|
|||
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
|
||||
use rustc_infer::traits::{ObligationCauseCode, ObligationInspector, WellFormedLoc};
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::config;
|
||||
use rustc_span::Span;
|
||||
|
|
@ -251,29 +251,10 @@ fn typeck_with_inspect<'tcx>(
|
|||
fcx.report_ambiguity_errors();
|
||||
}
|
||||
|
||||
if let None = fcx.infcx.tainted_by_errors() {
|
||||
fcx.check_transmutes();
|
||||
}
|
||||
|
||||
fcx.check_asms();
|
||||
|
||||
let typeck_results = fcx.resolve_type_vars_in_body(body);
|
||||
|
||||
// Handle potentially region dependent goals, see `InferCtxt::in_hir_typeck`.
|
||||
if let None = fcx.infcx.tainted_by_errors() {
|
||||
for obligation in fcx.take_hir_typeck_potentially_region_dependent_goals() {
|
||||
let obligation = fcx.resolve_vars_if_possible(obligation);
|
||||
if obligation.has_non_region_infer() {
|
||||
bug!("unexpected inference variable after writeback: {obligation:?}");
|
||||
}
|
||||
fcx.register_predicate(obligation);
|
||||
}
|
||||
fcx.select_obligations_where_possible(|_| {});
|
||||
if let None = fcx.infcx.tainted_by_errors() {
|
||||
fcx.report_ambiguity_errors();
|
||||
}
|
||||
}
|
||||
|
||||
fcx.detect_opaque_types_added_during_writeback();
|
||||
|
||||
// Consistency check our TypeckResults instance can hold all ItemLocalIds
|
||||
|
|
@ -555,6 +536,7 @@ pub fn provide(providers: &mut Providers) {
|
|||
method_autoderef_steps: method::probe::method_autoderef_steps,
|
||||
typeck,
|
||||
used_trait_imports,
|
||||
check_transmutes: intrinsicck::check_transmutes,
|
||||
..*providers
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,9 +13,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
|||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, DiagStyledString, MultiSpan, StashKey, pluralize, struct_span_code_err,
|
||||
};
|
||||
use rustc_errors::{Applicability, Diag, MultiSpan, StashKey, pluralize, struct_span_code_err};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
|
|
@ -1560,11 +1558,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
if rcvr_ty.is_numeric() && rcvr_ty.is_fresh()
|
||||
|| restrict_type_params
|
||||
|| suggested_derive
|
||||
|| self.lookup_alternative_tuple_impls(&mut err, &unsatisfied_predicates)
|
||||
{
|
||||
if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params || suggested_derive {
|
||||
} else {
|
||||
self.suggest_traits_to_import(
|
||||
&mut err,
|
||||
|
|
@ -1741,119 +1735,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
err.emit()
|
||||
}
|
||||
|
||||
/// If the predicate failure is caused by an unmet bound on a tuple, recheck if the bound would
|
||||
/// succeed if all the types on the tuple had no borrows. This is a common problem for libraries
|
||||
/// like Bevy and ORMs, which rely heavily on traits being implemented on tuples.
|
||||
fn lookup_alternative_tuple_impls(
|
||||
&self,
|
||||
err: &mut Diag<'_>,
|
||||
unsatisfied_predicates: &[(
|
||||
ty::Predicate<'tcx>,
|
||||
Option<ty::Predicate<'tcx>>,
|
||||
Option<ObligationCause<'tcx>>,
|
||||
)],
|
||||
) -> bool {
|
||||
let mut found_tuple = false;
|
||||
for (pred, root, _ob) in unsatisfied_predicates {
|
||||
let mut preds = vec![pred];
|
||||
if let Some(root) = root {
|
||||
// We will look at both the current predicate and the root predicate that caused it
|
||||
// to be needed. If calling something like `<(A, &B)>::default()`, then `pred` is
|
||||
// `&B: Default` and `root` is `(A, &B): Default`, which is the one we are checking
|
||||
// for further down, so we check both.
|
||||
preds.push(root);
|
||||
}
|
||||
for pred in preds {
|
||||
if let Some(clause) = pred.as_clause()
|
||||
&& let Some(clause) = clause.as_trait_clause()
|
||||
&& let ty = clause.self_ty().skip_binder()
|
||||
&& let ty::Tuple(types) = ty.kind()
|
||||
{
|
||||
let path = clause.skip_binder().trait_ref.print_only_trait_path();
|
||||
let def_id = clause.def_id();
|
||||
let ty = Ty::new_tup(
|
||||
self.tcx,
|
||||
self.tcx.mk_type_list_from_iter(types.iter().map(|ty| ty.peel_refs())),
|
||||
);
|
||||
let args = ty::GenericArgs::for_item(self.tcx, def_id, |param, _| {
|
||||
if param.index == 0 {
|
||||
ty.into()
|
||||
} else {
|
||||
self.infcx.var_for_def(DUMMY_SP, param)
|
||||
}
|
||||
});
|
||||
if self
|
||||
.infcx
|
||||
.type_implements_trait(def_id, args, self.param_env)
|
||||
.must_apply_modulo_regions()
|
||||
{
|
||||
// "`Trait` is implemented for `(A, B)` but not for `(A, &B)`"
|
||||
let mut msg = DiagStyledString::normal(format!("`{path}` "));
|
||||
msg.push_highlighted("is");
|
||||
msg.push_normal(" implemented for `(");
|
||||
let len = types.len();
|
||||
for (i, t) in types.iter().enumerate() {
|
||||
msg.push(
|
||||
format!("{}", with_forced_trimmed_paths!(t.peel_refs())),
|
||||
t.peel_refs() != t,
|
||||
);
|
||||
if i < len - 1 {
|
||||
msg.push_normal(", ");
|
||||
}
|
||||
}
|
||||
msg.push_normal(")` but ");
|
||||
msg.push_highlighted("not");
|
||||
msg.push_normal(" for `(");
|
||||
for (i, t) in types.iter().enumerate() {
|
||||
msg.push(
|
||||
format!("{}", with_forced_trimmed_paths!(t)),
|
||||
t.peel_refs() != t,
|
||||
);
|
||||
if i < len - 1 {
|
||||
msg.push_normal(", ");
|
||||
}
|
||||
}
|
||||
msg.push_normal(")`");
|
||||
|
||||
// Find the span corresponding to the impl that was found to point at it.
|
||||
if let Some(impl_span) = self
|
||||
.tcx
|
||||
.all_impls(def_id)
|
||||
.filter(|&impl_def_id| {
|
||||
let header = self.tcx.impl_trait_header(impl_def_id).unwrap();
|
||||
let trait_ref = header.trait_ref.instantiate(
|
||||
self.tcx,
|
||||
self.infcx.fresh_args_for_item(DUMMY_SP, impl_def_id),
|
||||
);
|
||||
|
||||
let value = ty::fold_regions(self.tcx, ty, |_, _| {
|
||||
self.tcx.lifetimes.re_erased
|
||||
});
|
||||
// FIXME: Don't bother dealing with non-lifetime binders here...
|
||||
if value.has_escaping_bound_vars() {
|
||||
return false;
|
||||
}
|
||||
self.infcx.can_eq(ty::ParamEnv::empty(), trait_ref.self_ty(), value)
|
||||
&& header.polarity == ty::ImplPolarity::Positive
|
||||
})
|
||||
.map(|impl_def_id| self.tcx.def_span(impl_def_id))
|
||||
.next()
|
||||
{
|
||||
err.highlighted_span_note(impl_span, msg.0);
|
||||
} else {
|
||||
err.highlighted_note(msg.0);
|
||||
}
|
||||
found_tuple = true;
|
||||
}
|
||||
// If `pred` was already on the tuple, we don't need to look at the root
|
||||
// obligation too.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
found_tuple
|
||||
}
|
||||
|
||||
/// If an appropriate error source is not found, check method chain for possible candidates
|
||||
fn lookup_segments_chain_for_no_match_method(
|
||||
&self,
|
||||
|
|
|
|||
|
|
@ -74,7 +74,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
wbcx.visit_user_provided_tys();
|
||||
wbcx.visit_user_provided_sigs();
|
||||
wbcx.visit_coroutine_interior();
|
||||
wbcx.visit_transmutes();
|
||||
wbcx.visit_offset_of_container_types();
|
||||
wbcx.visit_potentially_region_dependent_goals();
|
||||
|
||||
wbcx.typeck_results.rvalue_scopes =
|
||||
mem::take(&mut self.typeck_results.borrow_mut().rvalue_scopes);
|
||||
|
|
@ -532,6 +534,18 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn visit_transmutes(&mut self) {
|
||||
let tcx = self.tcx();
|
||||
let fcx_typeck_results = self.fcx.typeck_results.borrow();
|
||||
assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
|
||||
for &(from, to, hir_id) in self.fcx.deferred_transmute_checks.borrow().iter() {
|
||||
let span = tcx.hir_span(hir_id);
|
||||
let from = self.resolve(from, &span);
|
||||
let to = self.resolve(to, &span);
|
||||
self.typeck_results.transmutes_to_check.push((from, to, hir_id));
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn visit_opaque_types(&mut self) {
|
||||
let tcx = self.tcx();
|
||||
|
|
@ -762,6 +776,32 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn visit_potentially_region_dependent_goals(&mut self) {
|
||||
let obligations = self.fcx.take_hir_typeck_potentially_region_dependent_goals();
|
||||
if let None = self.fcx.tainted_by_errors() {
|
||||
for obligation in obligations {
|
||||
let (predicate, mut cause) =
|
||||
self.fcx.resolve_vars_if_possible((obligation.predicate, obligation.cause));
|
||||
if predicate.has_non_region_infer() {
|
||||
self.fcx.dcx().span_delayed_bug(
|
||||
cause.span,
|
||||
format!("unexpected inference variable after writeback: {predicate:?}"),
|
||||
);
|
||||
} else {
|
||||
let predicate = self.tcx().erase_regions(predicate);
|
||||
if cause.has_infer() || cause.has_placeholders() {
|
||||
// We can't use the the obligation cause as it references
|
||||
// information local to this query.
|
||||
cause = self.fcx.misc(cause.span);
|
||||
}
|
||||
self.typeck_results
|
||||
.potentially_region_dependent_goals
|
||||
.insert((predicate, cause));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve<T>(&mut self, value: T, span: &dyn Locatable) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
|
|
|
|||
|
|
@ -22,10 +22,6 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
|
|||
self.next_trait_solver
|
||||
}
|
||||
|
||||
fn in_hir_typeck(&self) -> bool {
|
||||
self.in_hir_typeck
|
||||
}
|
||||
|
||||
fn typing_mode(&self) -> ty::TypingMode<'tcx> {
|
||||
self.typing_mode()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,7 +158,8 @@ pub struct InferCtxtInner<'tcx> {
|
|||
region_assumptions: Vec<ty::ArgOutlivesPredicate<'tcx>>,
|
||||
|
||||
/// `-Znext-solver`: Successfully proven goals during HIR typeck which
|
||||
/// reference inference variables and get reproven after writeback.
|
||||
/// reference inference variables and get reproven in case MIR type check
|
||||
/// fails to prove something.
|
||||
///
|
||||
/// See the documentation of `InferCtxt::in_hir_typeck` for more details.
|
||||
hir_typeck_potentially_region_dependent_goals: Vec<PredicateObligation<'tcx>>,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use std::sync::{Arc, LazyLock, OnceLock};
|
|||
use std::{env, fs, iter};
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_attr_parsing::validate_attr;
|
||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||
use rustc_data_structures::jobserver::Proxy;
|
||||
use rustc_data_structures::steal::Steal;
|
||||
|
|
@ -25,9 +26,7 @@ use rustc_middle::arena::Arena;
|
|||
use rustc_middle::dep_graph::DepsType;
|
||||
use rustc_middle::ty::{self, CurrentGcx, GlobalCtxt, RegisteredTools, TyCtxt};
|
||||
use rustc_middle::util::Providers;
|
||||
use rustc_parse::{
|
||||
new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal, validate_attr,
|
||||
};
|
||||
use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
|
||||
use rustc_passes::{abi_test, input_stats, layout_test};
|
||||
use rustc_resolve::{Resolver, ResolverOutputs};
|
||||
use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType};
|
||||
|
|
@ -1081,7 +1080,8 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
|
|||
if !tcx.is_typeck_child(def_id.to_def_id()) {
|
||||
// Child unsafety and borrowck happens together with the parent
|
||||
tcx.ensure_ok().check_unsafety(def_id);
|
||||
tcx.ensure_ok().mir_borrowck(def_id)
|
||||
tcx.ensure_ok().mir_borrowck(def_id);
|
||||
tcx.ensure_ok().check_transmutes(def_id);
|
||||
}
|
||||
tcx.ensure_ok().has_ffi_unwind_calls(def_id);
|
||||
|
||||
|
|
|
|||
|
|
@ -5,14 +5,15 @@ use std::sync::{Arc, OnceLock};
|
|||
use std::{env, thread};
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_attr_parsing::validate_attr;
|
||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||
use rustc_data_structures::jobserver::Proxy;
|
||||
use rustc_data_structures::sync;
|
||||
use rustc_errors::LintBuffer;
|
||||
use rustc_metadata::{DylibError, load_symbol_from_dylib};
|
||||
use rustc_middle::ty::CurrentGcx;
|
||||
use rustc_parse::validate_attr;
|
||||
use rustc_session::config::{Cfg, OutFileName, OutputFilenames, OutputTypes, Sysroot, host_tuple};
|
||||
use rustc_session::lint::{self, BuiltinLintDiag, LintBuffer};
|
||||
use rustc_session::lint::{self, BuiltinLintDiag};
|
||||
use rustc_session::output::{CRATE_TYPES, categorize_crate_type};
|
||||
use rustc_session::{EarlyDiagCtxt, Session, filesearch};
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
|
|
|
|||
|
|
@ -540,11 +540,11 @@ impl Cursor<'_> {
|
|||
// whitespace between the opening and the infostring.
|
||||
self.eat_while(|ch| ch != '\n' && is_whitespace(ch));
|
||||
|
||||
// copied from `eat_identifier`, but allows `.` in infostring to allow something like
|
||||
// copied from `eat_identifier`, but allows `-` and `.` in infostring to allow something like
|
||||
// `---Cargo.toml` as a valid opener
|
||||
if is_id_start(self.first()) {
|
||||
self.bump();
|
||||
self.eat_while(|c| is_id_continue(c) || c == '.');
|
||||
self.eat_while(|c| is_id_continue(c) || c == '-' || c == '.');
|
||||
}
|
||||
|
||||
self.eat_while(|ch| ch != '\n' && is_whitespace(ch));
|
||||
|
|
|
|||
|
|
@ -205,8 +205,6 @@ lint_confusable_identifier_pair = found both `{$existing_sym}` and `{$sym}` as i
|
|||
.current_use = this identifier can be confused with `{$existing_sym}`
|
||||
.other_use = other identifier used here
|
||||
|
||||
lint_custom_inner_attribute_unstable = custom inner attributes are unstable
|
||||
|
||||
lint_dangling_pointers_from_locals = a dangling pointer will be produced because the local variable `{$local_var_name}` will be dropped
|
||||
.ret_ty = return type of the {$fn_kind} is `{$ret_ty}`
|
||||
.local_var = `{$local_var_name}` is part the {$fn_kind} and will be dropped at the end of the {$fn_kind}
|
||||
|
|
@ -271,10 +269,6 @@ lint_expectation = this lint expectation is unfulfilled
|
|||
lint_extern_crate_not_idiomatic = `extern crate` is not idiomatic in the new edition
|
||||
.suggestion = convert it to a `use`
|
||||
|
||||
lint_extern_without_abi = `extern` declarations without an explicit ABI are deprecated
|
||||
.label = ABI should be specified here
|
||||
.suggestion = explicitly specify the {$default_abi} ABI
|
||||
|
||||
lint_for_loops_over_fallibles =
|
||||
for loop over {$article} `{$ref_prefix}{$ty}`. This is more readably written as an `if let` statement
|
||||
.suggestion = consider using `if let` to clear intent
|
||||
|
|
@ -294,19 +288,6 @@ lint_hidden_glob_reexport = private item shadows public glob re-export
|
|||
|
||||
lint_hidden_lifetime_parameters = hidden lifetime parameters in types are deprecated
|
||||
|
||||
lint_hidden_unicode_codepoints = unicode codepoint changing visible direction of text present in {$label}
|
||||
.label = this {$label} contains {$count ->
|
||||
[one] an invisible
|
||||
*[other] invisible
|
||||
} unicode text flow control {$count ->
|
||||
[one] codepoint
|
||||
*[other] codepoints
|
||||
}
|
||||
.note = these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
|
||||
.suggestion_remove = if their presence wasn't intentional, you can remove them
|
||||
.suggestion_escape = if you want to keep them but make them visible in your source code, you can escape them
|
||||
.no_suggestion_note_escape = if you want to keep them but make them visible in your source code, you can escape them: {$escaped}
|
||||
|
||||
lint_identifier_non_ascii_char = identifier contains non-ASCII characters
|
||||
|
||||
lint_identifier_uncommon_codepoints = identifier contains {$codepoints_len ->
|
||||
|
|
@ -431,8 +412,6 @@ lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive
|
|||
lint_incomplete_include =
|
||||
include macro expected single expression in source
|
||||
|
||||
lint_inner_macro_attribute_unstable = inner macro attributes are unstable
|
||||
|
||||
lint_invalid_asm_label_binary = avoid using labels containing only the digits `0` and `1` in inline assembly
|
||||
.label = use a different label that doesn't start with `0` or `1`
|
||||
.help = start numbering with `2` instead
|
||||
|
|
@ -870,10 +849,6 @@ lint_undropped_manually_drops = calls to `std::mem::drop` with `std::mem::Manual
|
|||
.label = argument has type `{$arg_ty}`
|
||||
.suggestion = use `std::mem::ManuallyDrop::into_inner` to get the inner value
|
||||
|
||||
lint_unexpected_builtin_cfg = unexpected `--cfg {$cfg}` flag
|
||||
.controlled_by = config `{$cfg_name}` is only supposed to be controlled by `{$controlled_by}`
|
||||
.incoherent = manually setting a built-in cfg can and does create incoherent behaviors
|
||||
|
||||
lint_unexpected_cfg_add_build_rs_println = or consider adding `{$build_rs_println}` to the top of the `build.rs`
|
||||
lint_unexpected_cfg_add_cargo_feature = consider using a Cargo feature instead
|
||||
lint_unexpected_cfg_add_cargo_toml_lint_cfg = or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:{$cargo_toml_lint_cfg}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use rustc_ast::util::parser::ExprPrecedence;
|
|||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::sync;
|
||||
use rustc_data_structures::unord::UnordMap;
|
||||
use rustc_errors::{Diag, LintDiagnostic, MultiSpan};
|
||||
use rustc_errors::{Diag, LintBuffer, LintDiagnostic, MultiSpan};
|
||||
use rustc_feature::Features;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def_id::{CrateNum, DefId};
|
||||
|
|
@ -23,7 +23,7 @@ use rustc_middle::middle::privacy::EffectiveVisibilities;
|
|||
use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
|
||||
use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, Printer, with_no_trimmed_paths};
|
||||
use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingEnv, TypingMode};
|
||||
use rustc_session::lint::{FutureIncompatibleInfo, Lint, LintBuffer, LintExpectationId, LintId};
|
||||
use rustc_session::lint::{FutureIncompatibleInfo, Lint, LintExpectationId, LintId};
|
||||
use rustc_session::{DynLintStore, Session};
|
||||
use rustc_span::edit_distance::find_best_match_for_names;
|
||||
use rustc_span::{Ident, Span, Symbol, sym};
|
||||
|
|
|
|||
|
|
@ -7,10 +7,11 @@
|
|||
use rustc_ast::visit::{self as ast_visit, Visitor, walk_list};
|
||||
use rustc_ast::{self as ast, HasAttrs};
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_errors::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer};
|
||||
use rustc_feature::Features;
|
||||
use rustc_middle::ty::{RegisteredTools, TyCtxt};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::lint::{BufferedEarlyLint, LintBuffer, LintPass};
|
||||
use rustc_session::lint::LintPass;
|
||||
use rustc_span::{Ident, Span};
|
||||
use tracing::debug;
|
||||
|
||||
|
|
@ -36,8 +37,11 @@ impl<'ecx, 'tcx, T: EarlyLintPass> EarlyContextAndPass<'ecx, 'tcx, T> {
|
|||
fn check_id(&mut self, id: ast::NodeId) {
|
||||
for early_lint in self.context.buffered.take(id) {
|
||||
let BufferedEarlyLint { span, node_id: _, lint_id, diagnostic } = early_lint;
|
||||
self.context.opt_span_lint(lint_id.lint, span, |diag| {
|
||||
diagnostics::decorate_builtin_lint(self.context.sess(), self.tcx, diagnostic, diag);
|
||||
self.context.opt_span_lint(lint_id.lint, span, |diag| match diagnostic {
|
||||
DecorateDiagCompat::Builtin(b) => {
|
||||
diagnostics::decorate_builtin_lint(self.context.sess(), self.tcx, b, diag);
|
||||
}
|
||||
DecorateDiagCompat::Dynamic(d) => d.decorate_lint_box(diag),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,9 +158,6 @@ pub fn decorate_builtin_lint(
|
|||
}
|
||||
.decorate_lint(diag);
|
||||
}
|
||||
BuiltinLintDiag::MissingAbi(label_span, default_abi) => {
|
||||
lints::MissingAbi { span: label_span, default_abi }.decorate_lint(diag);
|
||||
}
|
||||
BuiltinLintDiag::LegacyDeriveHelpers(label_span) => {
|
||||
lints::LegacyDeriveHelpers { span: label_span }.decorate_lint(diag);
|
||||
}
|
||||
|
|
@ -186,27 +183,6 @@ pub fn decorate_builtin_lint(
|
|||
lints::ReservedMultihash { suggestion }.decorate_lint(diag);
|
||||
}
|
||||
}
|
||||
BuiltinLintDiag::HiddenUnicodeCodepoints {
|
||||
label,
|
||||
count,
|
||||
span_label,
|
||||
labels,
|
||||
escape,
|
||||
spans,
|
||||
} => {
|
||||
lints::HiddenUnicodeCodepointsDiag {
|
||||
label: &label,
|
||||
count,
|
||||
span_label,
|
||||
labels: labels.map(|spans| lints::HiddenUnicodeCodepointsDiagLabels { spans }),
|
||||
sub: if escape {
|
||||
lints::HiddenUnicodeCodepointsDiagSub::Escape { spans }
|
||||
} else {
|
||||
lints::HiddenUnicodeCodepointsDiagSub::NoEscape { spans }
|
||||
},
|
||||
}
|
||||
.decorate_lint(diag);
|
||||
}
|
||||
BuiltinLintDiag::UnusedBuiltinAttribute {
|
||||
attr_name,
|
||||
macro_name,
|
||||
|
|
@ -466,17 +442,8 @@ pub fn decorate_builtin_lint(
|
|||
}
|
||||
.decorate_lint(diag)
|
||||
}
|
||||
BuiltinLintDiag::InnerAttributeUnstable { is_macro } => if is_macro {
|
||||
lints::InnerAttributeUnstable::InnerMacroAttribute
|
||||
} else {
|
||||
lints::InnerAttributeUnstable::CustomInnerAttribute
|
||||
}
|
||||
.decorate_lint(diag),
|
||||
BuiltinLintDiag::OutOfScopeMacroCalls { span, path, location } => {
|
||||
lints::OutOfScopeMacroCalls { span, path, location }.decorate_lint(diag)
|
||||
}
|
||||
BuiltinLintDiag::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by } => {
|
||||
lints::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by }.decorate_lint(diag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,10 +133,9 @@ pub use early::{EarlyCheckNode, check_ast_node};
|
|||
pub use late::{check_crate, late_lint_mod, unerased_lint_store};
|
||||
pub use levels::LintLevelsBuilder;
|
||||
pub use passes::{EarlyLintPass, LateLintPass};
|
||||
pub use rustc_errors::BufferedEarlyLint;
|
||||
pub use rustc_session::lint::Level::{self, *};
|
||||
pub use rustc_session::lint::{
|
||||
BufferedEarlyLint, FutureIncompatibleInfo, Lint, LintId, LintPass, LintVec,
|
||||
};
|
||||
pub use rustc_session::lint::{FutureIncompatibleInfo, Lint, LintId, LintPass, LintVec};
|
||||
|
||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
use std::num::NonZero;
|
||||
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString, ElidedLifetimeInPathSubdiag,
|
||||
|
|
@ -816,80 +815,6 @@ pub(crate) enum InvalidReferenceCastingDiag<'tcx> {
|
|||
},
|
||||
}
|
||||
|
||||
// hidden_unicode_codepoints.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_hidden_unicode_codepoints)]
|
||||
#[note]
|
||||
pub(crate) struct HiddenUnicodeCodepointsDiag<'a> {
|
||||
pub label: &'a str,
|
||||
pub count: usize,
|
||||
#[label]
|
||||
pub span_label: Span,
|
||||
#[subdiagnostic]
|
||||
pub labels: Option<HiddenUnicodeCodepointsDiagLabels>,
|
||||
#[subdiagnostic]
|
||||
pub sub: HiddenUnicodeCodepointsDiagSub,
|
||||
}
|
||||
|
||||
pub(crate) struct HiddenUnicodeCodepointsDiagLabels {
|
||||
pub spans: Vec<(char, Span)>,
|
||||
}
|
||||
|
||||
impl Subdiagnostic for HiddenUnicodeCodepointsDiagLabels {
|
||||
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
|
||||
for (c, span) in self.spans {
|
||||
diag.span_label(span, format!("{c:?}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) enum HiddenUnicodeCodepointsDiagSub {
|
||||
Escape { spans: Vec<(char, Span)> },
|
||||
NoEscape { spans: Vec<(char, Span)> },
|
||||
}
|
||||
|
||||
// Used because of multiple multipart_suggestion and note
|
||||
impl Subdiagnostic for HiddenUnicodeCodepointsDiagSub {
|
||||
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
|
||||
match self {
|
||||
HiddenUnicodeCodepointsDiagSub::Escape { spans } => {
|
||||
diag.multipart_suggestion_with_style(
|
||||
fluent::lint_suggestion_remove,
|
||||
spans.iter().map(|(_, span)| (*span, "".to_string())).collect(),
|
||||
Applicability::MachineApplicable,
|
||||
SuggestionStyle::HideCodeAlways,
|
||||
);
|
||||
diag.multipart_suggestion(
|
||||
fluent::lint_suggestion_escape,
|
||||
spans
|
||||
.into_iter()
|
||||
.map(|(c, span)| {
|
||||
let c = format!("{c:?}");
|
||||
(span, c[1..c.len() - 1].to_string())
|
||||
})
|
||||
.collect(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
HiddenUnicodeCodepointsDiagSub::NoEscape { spans } => {
|
||||
// FIXME: in other suggestions we've reversed the inner spans of doc comments. We
|
||||
// should do the same here to provide the same good suggestions as we do for
|
||||
// literals above.
|
||||
diag.arg(
|
||||
"escaped",
|
||||
spans
|
||||
.into_iter()
|
||||
.map(|(c, _)| format!("{c:?}"))
|
||||
.collect::<Vec<String>>()
|
||||
.join(", "),
|
||||
);
|
||||
diag.note(fluent::lint_suggestion_remove);
|
||||
diag.note(fluent::lint_no_suggestion_note_escape);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// map_unit_fn.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_map_unit_fn)]
|
||||
|
|
@ -2566,16 +2491,6 @@ pub(crate) mod unexpected_cfg_value {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unexpected_builtin_cfg)]
|
||||
#[note(lint_controlled_by)]
|
||||
#[note(lint_incoherent)]
|
||||
pub(crate) struct UnexpectedBuiltinCfg {
|
||||
pub(crate) cfg: String,
|
||||
pub(crate) cfg_name: Symbol,
|
||||
pub(crate) controlled_by: &'static str,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_macro_use_deprecated)]
|
||||
#[help]
|
||||
|
|
@ -2689,14 +2604,6 @@ pub(crate) struct IllFormedAttributeInput {
|
|||
pub docs: &'static str,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
pub(crate) enum InnerAttributeUnstable {
|
||||
#[diag(lint_inner_macro_attribute_unstable)]
|
||||
InnerMacroAttribute,
|
||||
#[diag(lint_custom_inner_attribute_unstable)]
|
||||
CustomInnerAttribute,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unknown_diagnostic_attribute)]
|
||||
pub(crate) struct UnknownDiagnosticAttribute {
|
||||
|
|
@ -2889,14 +2796,6 @@ pub(crate) struct PatternsInFnsWithoutBodySub {
|
|||
pub ident: Ident,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_extern_without_abi)]
|
||||
pub(crate) struct MissingAbi {
|
||||
#[suggestion(code = "extern {default_abi}", applicability = "machine-applicable")]
|
||||
pub span: Span,
|
||||
pub default_abi: ExternAbi,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_legacy_derive_helpers)]
|
||||
pub(crate) struct LegacyDeriveHelpers {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ edition = "2024"
|
|||
|
||||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
rustc_abi = { path = "../rustc_abi" }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_error_messages = { path = "../rustc_error_messages" }
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_ast::AttrId;
|
||||
use rustc_ast::attr::AttributeExt;
|
||||
use rustc_ast::node_id::NodeId;
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_data_structures::stable_hasher::{
|
||||
HashStable, StableCompare, StableHasher, ToStableHashKey,
|
||||
};
|
||||
|
|
@ -648,7 +646,6 @@ pub enum BuiltinLintDiag {
|
|||
path: String,
|
||||
since_kind: DeprecatedSinceKind,
|
||||
},
|
||||
MissingAbi(Span, ExternAbi),
|
||||
UnusedDocComment(Span),
|
||||
UnusedBuiltinAttribute {
|
||||
attr_name: Symbol,
|
||||
|
|
@ -671,14 +668,6 @@ pub enum BuiltinLintDiag {
|
|||
is_string: bool,
|
||||
suggestion: Span,
|
||||
},
|
||||
HiddenUnicodeCodepoints {
|
||||
label: String,
|
||||
count: usize,
|
||||
span_label: Span,
|
||||
labels: Option<Vec<(char, Span)>>,
|
||||
escape: bool,
|
||||
spans: Vec<(char, Span)>,
|
||||
},
|
||||
TrailingMacro(bool, Ident),
|
||||
BreakWithLabelAndLoop(Span),
|
||||
UnicodeTextFlow(Span, String),
|
||||
|
|
@ -803,68 +792,11 @@ pub enum BuiltinLintDiag {
|
|||
suggestions: Vec<String>,
|
||||
docs: Option<&'static str>,
|
||||
},
|
||||
InnerAttributeUnstable {
|
||||
is_macro: bool,
|
||||
},
|
||||
OutOfScopeMacroCalls {
|
||||
span: Span,
|
||||
path: String,
|
||||
location: String,
|
||||
},
|
||||
UnexpectedBuiltinCfg {
|
||||
cfg: String,
|
||||
cfg_name: Symbol,
|
||||
controlled_by: &'static str,
|
||||
},
|
||||
}
|
||||
|
||||
/// Lints that are buffered up early on in the `Session` before the
|
||||
/// `LintLevels` is calculated.
|
||||
#[derive(Debug)]
|
||||
pub struct BufferedEarlyLint {
|
||||
/// The span of code that we are linting on.
|
||||
pub span: Option<MultiSpan>,
|
||||
|
||||
/// The `NodeId` of the AST node that generated the lint.
|
||||
pub node_id: NodeId,
|
||||
|
||||
/// A lint Id that can be passed to
|
||||
/// `rustc_lint::early::EarlyContextAndPass::check_id`.
|
||||
pub lint_id: LintId,
|
||||
|
||||
/// Customization of the `Diag<'_>` for the lint.
|
||||
pub diagnostic: BuiltinLintDiag,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct LintBuffer {
|
||||
pub map: FxIndexMap<NodeId, Vec<BufferedEarlyLint>>,
|
||||
}
|
||||
|
||||
impl LintBuffer {
|
||||
pub fn add_early_lint(&mut self, early_lint: BufferedEarlyLint) {
|
||||
self.map.entry(early_lint.node_id).or_default().push(early_lint);
|
||||
}
|
||||
|
||||
pub fn take(&mut self, id: NodeId) -> Vec<BufferedEarlyLint> {
|
||||
// FIXME(#120456) - is `swap_remove` correct?
|
||||
self.map.swap_remove(&id).unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn buffer_lint(
|
||||
&mut self,
|
||||
lint: &'static Lint,
|
||||
node_id: NodeId,
|
||||
span: impl Into<MultiSpan>,
|
||||
diagnostic: BuiltinLintDiag,
|
||||
) {
|
||||
self.add_early_lint(BufferedEarlyLint {
|
||||
lint_id: LintId::of(lint),
|
||||
node_id,
|
||||
span: Some(span.into()),
|
||||
diagnostic,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub type RegisteredTools = FxIndexSet<Ident>;
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@
|
|||
#![feature(try_trait_v2_residual)]
|
||||
#![feature(try_trait_v2_yeet)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
#![feature(unwrap_infallible)]
|
||||
#![feature(yeet_expr)]
|
||||
#![recursion_limit = "256"]
|
||||
// tidy-alphabetical-end
|
||||
|
|
|
|||
|
|
@ -72,13 +72,23 @@ pub struct CodegenFnAttrs {
|
|||
pub patchable_function_entry: Option<PatchableFunctionEntry>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable, PartialEq, Eq)]
|
||||
pub enum TargetFeatureKind {
|
||||
/// The feature is implied by another feature, rather than explicitly added by the
|
||||
/// `#[target_feature]` attribute
|
||||
Implied,
|
||||
/// The feature is added by the regular `target_feature` attribute.
|
||||
Enabled,
|
||||
/// The feature is added by the unsafe `force_target_feature` attribute.
|
||||
Forced,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||
pub struct TargetFeature {
|
||||
/// The name of the target feature (e.g. "avx")
|
||||
pub name: Symbol,
|
||||
/// The feature is implied by another feature, rather than explicitly added by the
|
||||
/// `#[target_feature]` attribute
|
||||
pub implied: bool,
|
||||
/// The way this feature was enabled.
|
||||
pub kind: TargetFeatureKind,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
use std::num::NonZero;
|
||||
|
||||
use rustc_ast::NodeId;
|
||||
use rustc_errors::{Applicability, Diag, EmissionGuarantee};
|
||||
use rustc_errors::{Applicability, Diag, EmissionGuarantee, LintBuffer};
|
||||
use rustc_feature::GateIssue;
|
||||
use rustc_hir::attrs::{DeprecatedSince, Deprecation};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
|
|
@ -12,7 +12,7 @@ use rustc_hir::{self as hir, ConstStability, DefaultBodyStability, HirId, Stabil
|
|||
use rustc_macros::{Decodable, Encodable, HashStable, Subdiagnostic};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE};
|
||||
use rustc_session::lint::{BuiltinLintDiag, DeprecatedSinceKind, Level, Lint, LintBuffer};
|
||||
use rustc_session::lint::{BuiltinLintDiag, DeprecatedSinceKind, Level, Lint};
|
||||
use rustc_session::parse::feature_err_issue;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use tracing::debug;
|
||||
|
|
|
|||
|
|
@ -120,6 +120,17 @@ impl<Prov: Provenance> ProvenanceMap<Prov> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Gets the provenances of all bytes (including from pointers) in a range.
|
||||
pub fn get_range(
|
||||
&self,
|
||||
cx: &impl HasDataLayout,
|
||||
range: AllocRange,
|
||||
) -> impl Iterator<Item = Prov> {
|
||||
let ptr_provs = self.range_ptrs_get(range, cx).iter().map(|(_, p)| *p);
|
||||
let byte_provs = self.range_bytes_get(range).iter().map(|(_, (p, _))| *p);
|
||||
ptr_provs.chain(byte_provs)
|
||||
}
|
||||
|
||||
/// Attempt to merge per-byte provenance back into ptr chunks, if the right fragments
|
||||
/// sit next to each other. Return `false` is that is not possible due to partial pointers.
|
||||
pub fn merge_bytes(&mut self, cx: &impl HasDataLayout) -> bool {
|
||||
|
|
|
|||
|
|
@ -548,10 +548,27 @@ impl<'tcx> CodegenUnit<'tcx> {
|
|||
|
||||
let mut items: Vec<_> = self.items().iter().map(|(&i, &data)| (i, data)).collect();
|
||||
if !tcx.sess.opts.unstable_opts.codegen_source_order {
|
||||
// It's already deterministic, so we can just use it.
|
||||
return items;
|
||||
// In this case, we do not need to keep the items in any specific order, as the input
|
||||
// is already deterministic.
|
||||
//
|
||||
// However, it seems that moving related things (such as different
|
||||
// monomorphizations of the same function) close to one another is actually beneficial
|
||||
// for LLVM performance.
|
||||
// LLVM will codegen the items in the order we pass them to it, and when it handles
|
||||
// similar things in succession, it seems that it leads to better cache utilization,
|
||||
// less branch mispredictions and in general to better performance.
|
||||
// For example, if we have functions `a`, `c::<u32>`, `b`, `c::<i16>`, `d` and
|
||||
// `c::<bool>`, it seems that it helps LLVM's performance to codegen the three `c`
|
||||
// instantiations right after one another, as they will likely reference similar types,
|
||||
// call similar functions, etc.
|
||||
//
|
||||
// See https://github.com/rust-lang/rust/pull/145358 for more details.
|
||||
//
|
||||
// Sorting by symbol name should not incur any new non-determinism.
|
||||
items.sort_by_cached_key(|&(i, _)| i.symbol_name(tcx));
|
||||
} else {
|
||||
items.sort_by_cached_key(|&(i, _)| item_sort_key(tcx, i));
|
||||
}
|
||||
items.sort_by_cached_key(|&(i, _)| item_sort_key(tcx, i));
|
||||
items
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -160,7 +160,11 @@ impl<'tcx> PlaceTy<'tcx> {
|
|||
/// Convenience wrapper around `projection_ty_core` for `PlaceElem`,
|
||||
/// where we can just use the `Ty` that is already stored inline on
|
||||
/// field projection elems.
|
||||
pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> {
|
||||
pub fn projection_ty<V: ::std::fmt::Debug>(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
elem: ProjectionElem<V, Ty<'tcx>>,
|
||||
) -> PlaceTy<'tcx> {
|
||||
self.projection_ty_core(tcx, &elem, |ty| ty, |_, _, _, ty| ty, |ty| ty)
|
||||
}
|
||||
|
||||
|
|
@ -290,6 +294,36 @@ impl<V, T> ProjectionElem<V, T> {
|
|||
Self::UnwrapUnsafeBinder(..) => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the `ProjectionKind` associated to this projection.
|
||||
pub fn kind(self) -> ProjectionKind {
|
||||
self.try_map(|_| Some(()), |_| ()).unwrap()
|
||||
}
|
||||
|
||||
/// Apply functions to types and values in this projection and return the result.
|
||||
pub fn try_map<V2, T2>(
|
||||
self,
|
||||
v: impl FnOnce(V) -> Option<V2>,
|
||||
t: impl FnOnce(T) -> T2,
|
||||
) -> Option<ProjectionElem<V2, T2>> {
|
||||
Some(match self {
|
||||
ProjectionElem::Deref => ProjectionElem::Deref,
|
||||
ProjectionElem::Downcast(name, read_variant) => {
|
||||
ProjectionElem::Downcast(name, read_variant)
|
||||
}
|
||||
ProjectionElem::Field(f, ty) => ProjectionElem::Field(f, t(ty)),
|
||||
ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
|
||||
ProjectionElem::ConstantIndex { offset, min_length, from_end }
|
||||
}
|
||||
ProjectionElem::Subslice { from, to, from_end } => {
|
||||
ProjectionElem::Subslice { from, to, from_end }
|
||||
}
|
||||
ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(t(ty)),
|
||||
ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(t(ty)),
|
||||
ProjectionElem::UnwrapUnsafeBinder(ty) => ProjectionElem::UnwrapUnsafeBinder(t(ty)),
|
||||
ProjectionElem::Index(val) => ProjectionElem::Index(v(val)?),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Alias for projections as they appear in `UserTypeProjection`, where we
|
||||
|
|
|
|||
|
|
@ -696,6 +696,22 @@ rustc_queries! {
|
|||
return_result_from_ensure_ok
|
||||
}
|
||||
|
||||
/// Used in case `mir_borrowck` fails to prove an obligation. We generally assume that
|
||||
/// all goals we prove in MIR type check hold as we've already checked them in HIR typeck.
|
||||
///
|
||||
/// However, we replace each free region in the MIR body with a unique region inference
|
||||
/// variable. As we may rely on structural identity when proving goals this may cause a
|
||||
/// goal to no longer hold. We store obligations for which this may happen during HIR
|
||||
/// typeck in the `TypeckResults`. We then uniquify and reprove them in case MIR typeck
|
||||
/// encounters an unexpected error. We expect this to result in an error when used and
|
||||
/// delay a bug if it does not.
|
||||
query check_potentially_region_dependent_goals(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
|
||||
desc {
|
||||
|tcx| "reproving potentially region dependent HIR typeck goals for `{}",
|
||||
tcx.def_path_str(key)
|
||||
}
|
||||
}
|
||||
|
||||
/// MIR after our optimization passes have run. This is MIR that is ready
|
||||
/// for codegen. This is also the only query that can fetch non-local MIR, at present.
|
||||
query optimized_mir(key: DefId) -> &'tcx mir::Body<'tcx> {
|
||||
|
|
@ -1115,6 +1131,11 @@ rustc_queries! {
|
|||
desc { |tcx| "collecting all inherent impls for `{:?}`", key }
|
||||
}
|
||||
|
||||
/// Unsafety-check this `LocalDefId`.
|
||||
query check_transmutes(key: LocalDefId) {
|
||||
desc { |tcx| "check transmute calls inside `{}`", tcx.def_path_str(key) }
|
||||
}
|
||||
|
||||
/// Unsafety-check this `LocalDefId`.
|
||||
query check_unsafety(key: LocalDefId) {
|
||||
desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key) }
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ use rustc_errors::{
|
|||
Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, LintDiagnostic, LintEmitter, MultiSpan,
|
||||
};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def::{CtorKind, DefKind};
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
|
||||
use rustc_hir::definitions::{DefPathData, Definitions, DisambiguatorState};
|
||||
use rustc_hir::intravisit::VisitorExt;
|
||||
|
|
@ -52,7 +52,7 @@ use rustc_session::{Limit, Session};
|
|||
use rustc_span::def_id::{CRATE_DEF_ID, DefPathHash, StableCrateId};
|
||||
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
|
||||
use rustc_type_ir::TyKind::*;
|
||||
use rustc_type_ir::lang_items::TraitSolverLangItem;
|
||||
use rustc_type_ir::lang_items::{SolverLangItem, SolverTraitLangItem};
|
||||
pub use rustc_type_ir::lift::Lift;
|
||||
use rustc_type_ir::{
|
||||
CollectAndApply, Interner, TypeFlags, TypeFoldable, WithCachedTypeInfo, elaborate, search_graph,
|
||||
|
|
@ -93,6 +93,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
|
||||
type DefId = DefId;
|
||||
type LocalDefId = LocalDefId;
|
||||
type TraitId = DefId;
|
||||
type Span = Span;
|
||||
|
||||
type GenericArgs = ty::GenericArgsRef<'tcx>;
|
||||
|
|
@ -445,7 +446,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
}
|
||||
|
||||
fn fn_is_const(self, def_id: DefId) -> bool {
|
||||
debug_assert_matches!(self.def_kind(def_id), DefKind::Fn | DefKind::AssocFn);
|
||||
debug_assert_matches!(
|
||||
self.def_kind(def_id),
|
||||
DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(CtorOf::Struct, CtorKind::Fn)
|
||||
);
|
||||
self.is_conditionally_const(def_id)
|
||||
}
|
||||
|
||||
|
|
@ -480,20 +484,32 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
!self.codegen_fn_attrs(def_id).target_features.is_empty()
|
||||
}
|
||||
|
||||
fn require_lang_item(self, lang_item: TraitSolverLangItem) -> DefId {
|
||||
self.require_lang_item(trait_lang_item_to_lang_item(lang_item), DUMMY_SP)
|
||||
fn require_lang_item(self, lang_item: SolverLangItem) -> DefId {
|
||||
self.require_lang_item(solver_lang_item_to_lang_item(lang_item), DUMMY_SP)
|
||||
}
|
||||
|
||||
fn is_lang_item(self, def_id: DefId, lang_item: TraitSolverLangItem) -> bool {
|
||||
self.is_lang_item(def_id, trait_lang_item_to_lang_item(lang_item))
|
||||
fn require_trait_lang_item(self, lang_item: SolverTraitLangItem) -> DefId {
|
||||
self.require_lang_item(solver_trait_lang_item_to_lang_item(lang_item), DUMMY_SP)
|
||||
}
|
||||
|
||||
fn is_lang_item(self, def_id: DefId, lang_item: SolverLangItem) -> bool {
|
||||
self.is_lang_item(def_id, solver_lang_item_to_lang_item(lang_item))
|
||||
}
|
||||
|
||||
fn is_trait_lang_item(self, def_id: DefId, lang_item: SolverTraitLangItem) -> bool {
|
||||
self.is_lang_item(def_id, solver_trait_lang_item_to_lang_item(lang_item))
|
||||
}
|
||||
|
||||
fn is_default_trait(self, def_id: DefId) -> bool {
|
||||
self.is_default_trait(def_id)
|
||||
}
|
||||
|
||||
fn as_lang_item(self, def_id: DefId) -> Option<TraitSolverLangItem> {
|
||||
lang_item_to_trait_lang_item(self.lang_items().from_def_id(def_id)?)
|
||||
fn as_lang_item(self, def_id: DefId) -> Option<SolverLangItem> {
|
||||
lang_item_to_solver_lang_item(self.lang_items().from_def_id(def_id)?)
|
||||
}
|
||||
|
||||
fn as_trait_lang_item(self, def_id: DefId) -> Option<SolverTraitLangItem> {
|
||||
lang_item_to_solver_trait_lang_item(self.lang_items().from_def_id(def_id)?)
|
||||
}
|
||||
|
||||
fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator<Item = DefId> {
|
||||
|
|
@ -724,16 +740,19 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||
}
|
||||
|
||||
macro_rules! bidirectional_lang_item_map {
|
||||
($($name:ident),+ $(,)?) => {
|
||||
fn trait_lang_item_to_lang_item(lang_item: TraitSolverLangItem) -> LangItem {
|
||||
(
|
||||
$solver_ty:ident, $to_solver:ident, $from_solver:ident;
|
||||
$($name:ident),+ $(,)?
|
||||
) => {
|
||||
fn $from_solver(lang_item: $solver_ty) -> LangItem {
|
||||
match lang_item {
|
||||
$(TraitSolverLangItem::$name => LangItem::$name,)+
|
||||
$($solver_ty::$name => LangItem::$name,)+
|
||||
}
|
||||
}
|
||||
|
||||
fn lang_item_to_trait_lang_item(lang_item: LangItem) -> Option<TraitSolverLangItem> {
|
||||
fn $to_solver(lang_item: LangItem) -> Option<$solver_ty> {
|
||||
Some(match lang_item {
|
||||
$(LangItem::$name => TraitSolverLangItem::$name,)+
|
||||
$(LangItem::$name => $solver_ty::$name,)+
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
|
@ -741,40 +760,50 @@ macro_rules! bidirectional_lang_item_map {
|
|||
}
|
||||
|
||||
bidirectional_lang_item_map! {
|
||||
SolverLangItem, lang_item_to_solver_lang_item, solver_lang_item_to_lang_item;
|
||||
|
||||
// tidy-alphabetical-start
|
||||
AsyncFnKindUpvars,
|
||||
AsyncFnOnceOutput,
|
||||
CallOnceFuture,
|
||||
CallRefFuture,
|
||||
CoroutineReturn,
|
||||
CoroutineYield,
|
||||
DynMetadata,
|
||||
FutureOutput,
|
||||
Metadata,
|
||||
Option,
|
||||
Poll,
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
||||
bidirectional_lang_item_map! {
|
||||
SolverTraitLangItem, lang_item_to_solver_trait_lang_item, solver_trait_lang_item_to_lang_item;
|
||||
|
||||
// tidy-alphabetical-start
|
||||
AsyncFn,
|
||||
AsyncFnKindHelper,
|
||||
AsyncFnKindUpvars,
|
||||
AsyncFnMut,
|
||||
AsyncFnOnce,
|
||||
AsyncFnOnceOutput,
|
||||
AsyncIterator,
|
||||
BikeshedGuaranteedNoDrop,
|
||||
CallOnceFuture,
|
||||
CallRefFuture,
|
||||
Clone,
|
||||
Copy,
|
||||
Coroutine,
|
||||
CoroutineReturn,
|
||||
CoroutineYield,
|
||||
Destruct,
|
||||
DiscriminantKind,
|
||||
Drop,
|
||||
DynMetadata,
|
||||
Fn,
|
||||
FnMut,
|
||||
FnOnce,
|
||||
FnPtrTrait,
|
||||
FusedIterator,
|
||||
Future,
|
||||
FutureOutput,
|
||||
Iterator,
|
||||
MetaSized,
|
||||
Metadata,
|
||||
Option,
|
||||
PointeeSized,
|
||||
PointeeTrait,
|
||||
Poll,
|
||||
Sized,
|
||||
TransmuteTrait,
|
||||
Tuple,
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ use rustc_data_structures::intern::Interned;
|
|||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::steal::Steal;
|
||||
use rustc_data_structures::unord::{UnordMap, UnordSet};
|
||||
use rustc_errors::{Diag, ErrorGuaranteed};
|
||||
use rustc_errors::{Diag, ErrorGuaranteed, LintBuffer};
|
||||
use rustc_hir::attrs::{AttributeKind, StrippedCfgItem};
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap};
|
||||
|
|
@ -46,7 +46,6 @@ use rustc_macros::{
|
|||
};
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
use rustc_serialize::{Decodable, Encodable};
|
||||
use rustc_session::lint::LintBuffer;
|
||||
pub use rustc_session::lint::RegisteredTools;
|
||||
use rustc_span::hygiene::MacroKind;
|
||||
use rustc_span::{DUMMY_SP, ExpnId, ExpnKind, Ident, Span, Symbol, sym};
|
||||
|
|
|
|||
|
|
@ -206,10 +206,25 @@ pub struct TypeckResults<'tcx> {
|
|||
/// formatting modified file tests/ui/coroutine/retain-resume-ref.rs
|
||||
pub coroutine_stalled_predicates: FxIndexSet<(ty::Predicate<'tcx>, ObligationCause<'tcx>)>,
|
||||
|
||||
/// Goals proven during HIR typeck which may be potentially region dependent.
|
||||
///
|
||||
/// Borrowck *uniquifies* regions which may cause these goal to be ambiguous in MIR
|
||||
/// type check. We ICE if goals fail in borrowck to detect bugs during MIR building or
|
||||
/// missed checks in HIR typeck. To avoid ICE due to region dependence we store all
|
||||
/// goals which may be region dependent and reprove them in case borrowck encounters
|
||||
/// an error.
|
||||
pub potentially_region_dependent_goals:
|
||||
FxIndexSet<(ty::Predicate<'tcx>, ObligationCause<'tcx>)>,
|
||||
|
||||
/// Contains the data for evaluating the effect of feature `capture_disjoint_fields`
|
||||
/// on closure size.
|
||||
pub closure_size_eval: LocalDefIdMap<ClosureSizeProfileData<'tcx>>,
|
||||
|
||||
/// Stores the types involved in calls to `transmute` intrinsic. These are meant to be checked
|
||||
/// outside of typeck and borrowck to avoid cycles with opaque types and coroutine layout
|
||||
/// computation.
|
||||
pub transmutes_to_check: Vec<(Ty<'tcx>, Ty<'tcx>, HirId)>,
|
||||
|
||||
/// Container types and field indices of `offset_of!` expressions
|
||||
offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec<(VariantIdx, FieldIdx)>)>,
|
||||
}
|
||||
|
|
@ -240,7 +255,9 @@ impl<'tcx> TypeckResults<'tcx> {
|
|||
closure_fake_reads: Default::default(),
|
||||
rvalue_scopes: Default::default(),
|
||||
coroutine_stalled_predicates: Default::default(),
|
||||
potentially_region_dependent_goals: Default::default(),
|
||||
closure_size_eval: Default::default(),
|
||||
transmutes_to_check: Default::default(),
|
||||
offset_of_data: Default::default(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use rustc_errors::DiagArgValue;
|
|||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability, find_attr};
|
||||
use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
|
||||
use rustc_middle::middle::codegen_fn_attrs::{TargetFeature, TargetFeatureKind};
|
||||
use rustc_middle::mir::BorrowKind;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::thir::visit::Visitor;
|
||||
|
|
@ -522,7 +522,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
|||
.iter()
|
||||
.copied()
|
||||
.filter(|feature| {
|
||||
!feature.implied
|
||||
feature.kind == TargetFeatureKind::Enabled
|
||||
&& !self
|
||||
.body_target_features
|
||||
.iter()
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
//! The move-analysis portion of borrowck needs to work in an abstract
|
||||
//! domain of lifted `Place`s. Most of the `Place` variants fall into a
|
||||
//! one-to-one mapping between the concrete and abstract (e.g., a
|
||||
//! field-deref on a local variable, `x.field`, has the same meaning
|
||||
//! in both domains). Indexed projections are the exception: `a[x]`
|
||||
//! needs to be treated as mapping to the same move path as `a[y]` as
|
||||
//! well as `a[13]`, etc. So we map these `x`/`y` values to `()`.
|
||||
//!
|
||||
//! (In theory, the analysis could be extended to work with sets of
|
||||
//! paths, so that `a[0]` and `a[13]` could be kept distinct, while
|
||||
//! `a[x]` would still overlap them both. But that is not this
|
||||
//! representation does today.)
|
||||
|
||||
use rustc_middle::mir::{PlaceElem, ProjectionElem, ProjectionKind};
|
||||
|
||||
pub(crate) trait Lift {
|
||||
fn lift(&self) -> ProjectionKind;
|
||||
}
|
||||
|
||||
impl<'tcx> Lift for PlaceElem<'tcx> {
|
||||
fn lift(&self) -> ProjectionKind {
|
||||
match *self {
|
||||
ProjectionElem::Deref => ProjectionElem::Deref,
|
||||
ProjectionElem::Field(f, _ty) => ProjectionElem::Field(f, ()),
|
||||
ProjectionElem::OpaqueCast(_ty) => ProjectionElem::OpaqueCast(()),
|
||||
ProjectionElem::Index(_i) => ProjectionElem::Index(()),
|
||||
ProjectionElem::Subslice { from, to, from_end } => {
|
||||
ProjectionElem::Subslice { from, to, from_end }
|
||||
}
|
||||
ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
|
||||
ProjectionElem::ConstantIndex { offset, min_length, from_end }
|
||||
}
|
||||
ProjectionElem::Downcast(a, u) => ProjectionElem::Downcast(a, u),
|
||||
ProjectionElem::Subtype(_ty) => ProjectionElem::Subtype(()),
|
||||
ProjectionElem::UnwrapUnsafeBinder(_ty) => ProjectionElem::UnwrapUnsafeBinder(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,7 +7,6 @@ use rustc_middle::{bug, span_bug};
|
|||
use smallvec::{SmallVec, smallvec};
|
||||
use tracing::debug;
|
||||
|
||||
use super::abs_domain::Lift;
|
||||
use super::{
|
||||
Init, InitIndex, InitKind, InitLocation, LocationMap, LookupResult, MoveData, MoveOut,
|
||||
MoveOutIndex, MovePath, MovePathIndex, MovePathLookup,
|
||||
|
|
@ -241,7 +240,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
|
|||
if union_path.is_none() {
|
||||
// inlined from add_move_path because of a borrowck conflict with the iterator
|
||||
base =
|
||||
*data.rev_lookup.projections.entry((base, elem.lift())).or_insert_with(|| {
|
||||
*data.rev_lookup.projections.entry((base, elem.kind())).or_insert_with(|| {
|
||||
new_move_path(
|
||||
&mut data.move_paths,
|
||||
&mut data.path_map,
|
||||
|
|
@ -272,7 +271,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
|
|||
tcx,
|
||||
..
|
||||
} = self;
|
||||
*rev_lookup.projections.entry((base, elem.lift())).or_insert_with(move || {
|
||||
*rev_lookup.projections.entry((base, elem.kind())).or_insert_with(move || {
|
||||
new_move_path(move_paths, path_map, init_path_map, Some(base), mk_place(*tcx))
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,15 @@
|
|||
//! The move-analysis portion of borrowck needs to work in an abstract domain of lifted `Place`s.
|
||||
//! Most of the `Place` variants fall into a one-to-one mapping between the concrete and abstract
|
||||
//! (e.g., a field projection on a local variable, `x.field`, has the same meaning in both
|
||||
//! domains). In other words, all field projections for the same field on the same local do not
|
||||
//! have meaningfully different types if ever. Indexed projections are the exception: `a[x]` needs
|
||||
//! to be treated as mapping to the same move path as `a[y]` as well as `a[13]`, etc. So we map
|
||||
//! these `x`/`y` values to `()`.
|
||||
//!
|
||||
//! (In theory, the analysis could be extended to work with sets of paths, so that `a[0]` and
|
||||
//! `a[13]` could be kept distinct, while `a[x]` would still overlap them both. But that is not
|
||||
//! what this representation does today.)
|
||||
|
||||
use std::fmt;
|
||||
use std::ops::{Index, IndexMut};
|
||||
|
||||
|
|
@ -8,11 +20,8 @@ use rustc_middle::ty::{Ty, TyCtxt};
|
|||
use rustc_span::Span;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use self::abs_domain::Lift;
|
||||
use crate::un_derefer::UnDerefer;
|
||||
|
||||
mod abs_domain;
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
#[orderable]
|
||||
#[debug_format = "mp{}"]
|
||||
|
|
@ -324,7 +333,7 @@ impl<'tcx> MovePathLookup<'tcx> {
|
|||
};
|
||||
|
||||
for (_, elem) in self.un_derefer.iter_projections(place) {
|
||||
if let Some(&subpath) = self.projections.get(&(result, elem.lift())) {
|
||||
if let Some(&subpath) = self.projections.get(&(result, elem.kind())) {
|
||||
result = subpath;
|
||||
} else {
|
||||
return LookupResult::Parent(Some(result));
|
||||
|
|
|
|||
|
|
@ -48,6 +48,21 @@ impl<'tcx> crate::MirPass<'tcx> for CheckEnums {
|
|||
let new_block = split_block(basic_blocks, location);
|
||||
|
||||
match check {
|
||||
EnumCheckType::Direct { op_size, .. }
|
||||
| EnumCheckType::WithNiche { op_size, .. }
|
||||
if op_size.bytes() == 0 =>
|
||||
{
|
||||
// It is never valid to use a ZST as a discriminant for an inhabited enum, but that will
|
||||
// have been caught by the type checker. Do nothing but ensure that a bug has been signaled.
|
||||
tcx.dcx().span_delayed_bug(
|
||||
source_info.span,
|
||||
"cannot build enum discriminant from zero-sized type",
|
||||
);
|
||||
basic_blocks[block].terminator = Some(Terminator {
|
||||
source_info,
|
||||
kind: TerminatorKind::Goto { target: new_block },
|
||||
});
|
||||
}
|
||||
EnumCheckType::Direct { source_op, discr, op_size, valid_discrs } => {
|
||||
insert_direct_enum_check(
|
||||
tcx,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
|
|||
|
||||
mod balanced_flow;
|
||||
pub(crate) mod node_flow;
|
||||
mod union_find;
|
||||
|
||||
/// Struct containing the results of [`prepare_bcb_counters_data`].
|
||||
pub(crate) struct BcbCountersData {
|
||||
|
|
|
|||
|
|
@ -7,13 +7,12 @@
|
|||
//! (Knuth & Stevenson, 1973).
|
||||
|
||||
use rustc_data_structures::graph;
|
||||
use rustc_data_structures::union_find::UnionFind;
|
||||
use rustc_index::bit_set::DenseBitSet;
|
||||
use rustc_index::{Idx, IndexSlice, IndexVec};
|
||||
pub(crate) use rustc_middle::mir::coverage::NodeFlowData;
|
||||
use rustc_middle::mir::coverage::Op;
|
||||
|
||||
use crate::coverage::counters::union_find::UnionFind;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
|
|
|
|||
|
|
@ -447,26 +447,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
|
||||
Projection(base, elem) => {
|
||||
let base = self.evaluated[base].as_ref()?;
|
||||
let elem = match elem {
|
||||
ProjectionElem::Deref => ProjectionElem::Deref,
|
||||
ProjectionElem::Downcast(name, read_variant) => {
|
||||
ProjectionElem::Downcast(name, read_variant)
|
||||
}
|
||||
ProjectionElem::Field(f, ()) => ProjectionElem::Field(f, ty.ty),
|
||||
ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
|
||||
ProjectionElem::ConstantIndex { offset, min_length, from_end }
|
||||
}
|
||||
ProjectionElem::Subslice { from, to, from_end } => {
|
||||
ProjectionElem::Subslice { from, to, from_end }
|
||||
}
|
||||
ProjectionElem::OpaqueCast(()) => ProjectionElem::OpaqueCast(ty.ty),
|
||||
ProjectionElem::Subtype(()) => ProjectionElem::Subtype(ty.ty),
|
||||
ProjectionElem::UnwrapUnsafeBinder(()) => {
|
||||
ProjectionElem::UnwrapUnsafeBinder(ty.ty)
|
||||
}
|
||||
// This should have been replaced by a `ConstantIndex` earlier.
|
||||
ProjectionElem::Index(_) => return None,
|
||||
};
|
||||
// `Index` by constants should have been replaced by `ConstantIndex` by
|
||||
// `simplify_place_projection`.
|
||||
let elem = elem.try_map(|_| None, |()| ty.ty)?;
|
||||
self.ecx.project(base, elem).discard_err()?
|
||||
}
|
||||
Address { place, kind: _, provenance: _ } => {
|
||||
|
|
@ -476,13 +459,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
let local = self.locals[place.local]?;
|
||||
let pointer = self.evaluated[local].as_ref()?;
|
||||
let mut mplace = self.ecx.deref_pointer(pointer).discard_err()?;
|
||||
for proj in place.projection.iter().skip(1) {
|
||||
// We have no call stack to associate a local with a value, so we cannot
|
||||
// interpret indexing.
|
||||
if matches!(proj, ProjectionElem::Index(_)) {
|
||||
return None;
|
||||
}
|
||||
mplace = self.ecx.project(&mplace, proj).discard_err()?;
|
||||
for elem in place.projection.iter().skip(1) {
|
||||
// `Index` by constants should have been replaced by `ConstantIndex` by
|
||||
// `simplify_place_projection`.
|
||||
let elem = elem.try_map(|_| None, |ty| ty)?;
|
||||
mplace = self.ecx.project(&mplace, elem).discard_err()?;
|
||||
}
|
||||
let pointer = mplace.to_ref(&self.ecx);
|
||||
ImmTy::from_immediate(pointer, ty).into()
|
||||
|
|
@ -902,27 +883,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
proj: ProjectionElem<VnIndex, ()>,
|
||||
loc: Location,
|
||||
) -> Option<PlaceElem<'tcx>> {
|
||||
Some(match proj {
|
||||
ProjectionElem::Deref => ProjectionElem::Deref,
|
||||
ProjectionElem::Field(idx, ()) => ProjectionElem::Field(idx, ty),
|
||||
ProjectionElem::Index(idx) => {
|
||||
let Some(local) = self.try_as_local(idx, loc) else {
|
||||
return None;
|
||||
};
|
||||
proj.try_map(
|
||||
|value| {
|
||||
let local = self.try_as_local(value, loc)?;
|
||||
self.reused_locals.insert(local);
|
||||
ProjectionElem::Index(local)
|
||||
}
|
||||
ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
|
||||
ProjectionElem::ConstantIndex { offset, min_length, from_end }
|
||||
}
|
||||
ProjectionElem::Subslice { from, to, from_end } => {
|
||||
ProjectionElem::Subslice { from, to, from_end }
|
||||
}
|
||||
ProjectionElem::Downcast(symbol, idx) => ProjectionElem::Downcast(symbol, idx),
|
||||
ProjectionElem::OpaqueCast(()) => ProjectionElem::OpaqueCast(ty),
|
||||
ProjectionElem::Subtype(()) => ProjectionElem::Subtype(ty),
|
||||
ProjectionElem::UnwrapUnsafeBinder(()) => ProjectionElem::UnwrapUnsafeBinder(ty),
|
||||
})
|
||||
Some(local)
|
||||
},
|
||||
|()| ty,
|
||||
)
|
||||
}
|
||||
|
||||
fn simplify_aggregate_to_copy(
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ impl<'tcx> crate::MirPass<'tcx> for ReferencePropagation {
|
|||
#[instrument(level = "trace", skip(self, tcx, body))]
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
debug!(def_id = ?body.source.def_id());
|
||||
move_to_copy_pointers(tcx, body);
|
||||
while propagate_ssa(tcx, body) {}
|
||||
}
|
||||
|
||||
|
|
@ -87,11 +88,43 @@ impl<'tcx> crate::MirPass<'tcx> for ReferencePropagation {
|
|||
}
|
||||
}
|
||||
|
||||
/// The SSA analysis done by [`SsaLocals`] treats [`Operand::Move`] as a read, even though in
|
||||
/// general [`Operand::Move`] represents pass-by-pointer where the callee can overwrite the
|
||||
/// pointee (Miri always considers the place deinitialized). CopyProp has a similar trick to
|
||||
/// turn [`Operand::Move`] into [`Operand::Copy`] when required for an optimization, but in this
|
||||
/// pass we just turn all moves of pointers into copies because pointers should be by-value anyway.
|
||||
fn move_to_copy_pointers<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
let mut visitor = MoveToCopyVisitor { tcx, local_decls: &body.local_decls };
|
||||
for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
|
||||
visitor.visit_basic_block_data(bb, data);
|
||||
}
|
||||
|
||||
struct MoveToCopyVisitor<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
local_decls: &'a IndexVec<Local, LocalDecl<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> MutVisitor<'tcx> for MoveToCopyVisitor<'a, 'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) {
|
||||
if let Operand::Move(place) = *operand {
|
||||
if place.ty(self.local_decls, self.tcx).ty.is_any_ptr() {
|
||||
*operand = Operand::Copy(place);
|
||||
}
|
||||
}
|
||||
self.super_operand(operand, loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
|
||||
let typing_env = body.typing_env(tcx);
|
||||
let ssa = SsaLocals::new(tcx, body, typing_env);
|
||||
|
||||
let mut replacer = compute_replacement(tcx, body, &ssa);
|
||||
let mut replacer = compute_replacement(tcx, body, ssa);
|
||||
debug!(?replacer.targets);
|
||||
debug!(?replacer.allowed_replacements);
|
||||
debug!(?replacer.storage_to_remove);
|
||||
|
|
@ -119,7 +152,7 @@ enum Value<'tcx> {
|
|||
fn compute_replacement<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
ssa: &SsaLocals,
|
||||
ssa: SsaLocals,
|
||||
) -> Replacer<'tcx> {
|
||||
let always_live_locals = always_storage_live_locals(body);
|
||||
|
||||
|
|
@ -138,7 +171,7 @@ fn compute_replacement<'tcx>(
|
|||
// reborrowed references.
|
||||
let mut storage_to_remove = DenseBitSet::new_empty(body.local_decls.len());
|
||||
|
||||
let fully_replaceable_locals = fully_replaceable_locals(ssa);
|
||||
let fully_replaceable_locals = fully_replaceable_locals(&ssa);
|
||||
|
||||
// Returns true iff we can use `place` as a pointee.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -25,12 +25,8 @@ enum CanonicalizeInputKind {
|
|||
/// trait candidates relies on it when deciding whether a where-bound
|
||||
/// is trivial.
|
||||
ParamEnv,
|
||||
/// When canonicalizing predicates, we don't keep `'static`. If we're
|
||||
/// currently outside of the trait solver and canonicalize the root goal
|
||||
/// during HIR typeck, we replace each occurrence of a region with a
|
||||
/// unique region variable. See the comment on `InferCtxt::in_hir_typeck`
|
||||
/// for more details.
|
||||
Predicate { is_hir_typeck_root_goal: bool },
|
||||
/// When canonicalizing predicates, we don't keep `'static`.
|
||||
Predicate,
|
||||
}
|
||||
|
||||
/// Whether we're canonicalizing a query input or the query response.
|
||||
|
|
@ -191,7 +187,6 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|||
pub fn canonicalize_input<P: TypeFoldable<I>>(
|
||||
delegate: &'a D,
|
||||
variables: &'a mut Vec<I::GenericArg>,
|
||||
is_hir_typeck_root_goal: bool,
|
||||
input: QueryInput<I, P>,
|
||||
) -> ty::Canonical<I, QueryInput<I, P>> {
|
||||
// First canonicalize the `param_env` while keeping `'static`
|
||||
|
|
@ -201,9 +196,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|||
// while *mostly* reusing the canonicalizer from above.
|
||||
let mut rest_canonicalizer = Canonicalizer {
|
||||
delegate,
|
||||
canonicalize_mode: CanonicalizeMode::Input(CanonicalizeInputKind::Predicate {
|
||||
is_hir_typeck_root_goal,
|
||||
}),
|
||||
canonicalize_mode: CanonicalizeMode::Input(CanonicalizeInputKind::Predicate),
|
||||
|
||||
variables,
|
||||
variable_lookup_table,
|
||||
|
|
@ -481,31 +474,13 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
|
|||
}
|
||||
};
|
||||
|
||||
let var = if let CanonicalizeMode::Input(CanonicalizeInputKind::Predicate {
|
||||
is_hir_typeck_root_goal: true,
|
||||
}) = self.canonicalize_mode
|
||||
{
|
||||
let var = ty::BoundVar::from(self.variables.len());
|
||||
self.variables.push(r.into());
|
||||
self.var_kinds.push(kind);
|
||||
var
|
||||
} else {
|
||||
self.get_or_insert_bound_var(r, kind)
|
||||
};
|
||||
let var = self.get_or_insert_bound_var(r, kind);
|
||||
|
||||
Region::new_anon_bound(self.cx(), self.binder_index, var)
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
|
||||
if let CanonicalizeMode::Input(CanonicalizeInputKind::Predicate {
|
||||
is_hir_typeck_root_goal: true,
|
||||
}) = self.canonicalize_mode
|
||||
{
|
||||
// If we're canonicalizing a root goal during HIR typeck, we
|
||||
// must not use the `cache` as we want to map each occurrence
|
||||
// of a region to a unique existential variable.
|
||||
self.inner_fold_ty(t)
|
||||
} else if let Some(&ty) = self.cache.get(&(self.binder_index, t)) {
|
||||
if let Some(&ty) = self.cache.get(&(self.binder_index, t)) {
|
||||
ty
|
||||
} else {
|
||||
let res = self.inner_fold_ty(t);
|
||||
|
|
|
|||
|
|
@ -295,7 +295,7 @@ where
|
|||
ControlFlow::Break(OrphanCheckEarlyExit::UncoveredTyParam(ty))
|
||||
}
|
||||
|
||||
fn def_id_is_local(&mut self, def_id: I::DefId) -> bool {
|
||||
fn def_id_is_local(&mut self, def_id: impl DefId<I>) -> bool {
|
||||
match self.in_crate {
|
||||
InCrate::Local { .. } => def_id.is_local(),
|
||||
InCrate::Remote => false,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use std::ops::ControlFlow;
|
|||
|
||||
use derive_where::derive_where;
|
||||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::lang_items::TraitSolverLangItem;
|
||||
use rustc_type_ir::lang_items::SolverTraitLangItem;
|
||||
use rustc_type_ir::search_graph::CandidateHeadUsages;
|
||||
use rustc_type_ir::solve::SizedTraitKind;
|
||||
use rustc_type_ir::{
|
||||
|
|
@ -54,7 +54,7 @@ where
|
|||
|
||||
fn with_replaced_self_ty(self, cx: I, self_ty: I::Ty) -> Self;
|
||||
|
||||
fn trait_def_id(self, cx: I) -> I::DefId;
|
||||
fn trait_def_id(self, cx: I) -> I::TraitId;
|
||||
|
||||
/// Consider a clause, which consists of a "assumption" and some "requirements",
|
||||
/// to satisfy a goal. If the requirements hold, then attempt to satisfy our
|
||||
|
|
@ -516,80 +516,80 @@ where
|
|||
} else if cx.trait_is_alias(trait_def_id) {
|
||||
G::consider_trait_alias_candidate(self, goal)
|
||||
} else {
|
||||
match cx.as_lang_item(trait_def_id) {
|
||||
Some(TraitSolverLangItem::Sized) => {
|
||||
match cx.as_trait_lang_item(trait_def_id) {
|
||||
Some(SolverTraitLangItem::Sized) => {
|
||||
G::consider_builtin_sizedness_candidates(self, goal, SizedTraitKind::Sized)
|
||||
}
|
||||
Some(TraitSolverLangItem::MetaSized) => {
|
||||
Some(SolverTraitLangItem::MetaSized) => {
|
||||
G::consider_builtin_sizedness_candidates(self, goal, SizedTraitKind::MetaSized)
|
||||
}
|
||||
Some(TraitSolverLangItem::PointeeSized) => {
|
||||
Some(SolverTraitLangItem::PointeeSized) => {
|
||||
unreachable!("`PointeeSized` is removed during lowering");
|
||||
}
|
||||
Some(TraitSolverLangItem::Copy | TraitSolverLangItem::Clone) => {
|
||||
Some(SolverTraitLangItem::Copy | SolverTraitLangItem::Clone) => {
|
||||
G::consider_builtin_copy_clone_candidate(self, goal)
|
||||
}
|
||||
Some(TraitSolverLangItem::Fn) => {
|
||||
Some(SolverTraitLangItem::Fn) => {
|
||||
G::consider_builtin_fn_trait_candidates(self, goal, ty::ClosureKind::Fn)
|
||||
}
|
||||
Some(TraitSolverLangItem::FnMut) => {
|
||||
Some(SolverTraitLangItem::FnMut) => {
|
||||
G::consider_builtin_fn_trait_candidates(self, goal, ty::ClosureKind::FnMut)
|
||||
}
|
||||
Some(TraitSolverLangItem::FnOnce) => {
|
||||
Some(SolverTraitLangItem::FnOnce) => {
|
||||
G::consider_builtin_fn_trait_candidates(self, goal, ty::ClosureKind::FnOnce)
|
||||
}
|
||||
Some(TraitSolverLangItem::AsyncFn) => {
|
||||
Some(SolverTraitLangItem::AsyncFn) => {
|
||||
G::consider_builtin_async_fn_trait_candidates(self, goal, ty::ClosureKind::Fn)
|
||||
}
|
||||
Some(TraitSolverLangItem::AsyncFnMut) => {
|
||||
Some(SolverTraitLangItem::AsyncFnMut) => {
|
||||
G::consider_builtin_async_fn_trait_candidates(
|
||||
self,
|
||||
goal,
|
||||
ty::ClosureKind::FnMut,
|
||||
)
|
||||
}
|
||||
Some(TraitSolverLangItem::AsyncFnOnce) => {
|
||||
Some(SolverTraitLangItem::AsyncFnOnce) => {
|
||||
G::consider_builtin_async_fn_trait_candidates(
|
||||
self,
|
||||
goal,
|
||||
ty::ClosureKind::FnOnce,
|
||||
)
|
||||
}
|
||||
Some(TraitSolverLangItem::FnPtrTrait) => {
|
||||
Some(SolverTraitLangItem::FnPtrTrait) => {
|
||||
G::consider_builtin_fn_ptr_trait_candidate(self, goal)
|
||||
}
|
||||
Some(TraitSolverLangItem::AsyncFnKindHelper) => {
|
||||
Some(SolverTraitLangItem::AsyncFnKindHelper) => {
|
||||
G::consider_builtin_async_fn_kind_helper_candidate(self, goal)
|
||||
}
|
||||
Some(TraitSolverLangItem::Tuple) => G::consider_builtin_tuple_candidate(self, goal),
|
||||
Some(TraitSolverLangItem::PointeeTrait) => {
|
||||
Some(SolverTraitLangItem::Tuple) => G::consider_builtin_tuple_candidate(self, goal),
|
||||
Some(SolverTraitLangItem::PointeeTrait) => {
|
||||
G::consider_builtin_pointee_candidate(self, goal)
|
||||
}
|
||||
Some(TraitSolverLangItem::Future) => {
|
||||
Some(SolverTraitLangItem::Future) => {
|
||||
G::consider_builtin_future_candidate(self, goal)
|
||||
}
|
||||
Some(TraitSolverLangItem::Iterator) => {
|
||||
Some(SolverTraitLangItem::Iterator) => {
|
||||
G::consider_builtin_iterator_candidate(self, goal)
|
||||
}
|
||||
Some(TraitSolverLangItem::FusedIterator) => {
|
||||
Some(SolverTraitLangItem::FusedIterator) => {
|
||||
G::consider_builtin_fused_iterator_candidate(self, goal)
|
||||
}
|
||||
Some(TraitSolverLangItem::AsyncIterator) => {
|
||||
Some(SolverTraitLangItem::AsyncIterator) => {
|
||||
G::consider_builtin_async_iterator_candidate(self, goal)
|
||||
}
|
||||
Some(TraitSolverLangItem::Coroutine) => {
|
||||
Some(SolverTraitLangItem::Coroutine) => {
|
||||
G::consider_builtin_coroutine_candidate(self, goal)
|
||||
}
|
||||
Some(TraitSolverLangItem::DiscriminantKind) => {
|
||||
Some(SolverTraitLangItem::DiscriminantKind) => {
|
||||
G::consider_builtin_discriminant_kind_candidate(self, goal)
|
||||
}
|
||||
Some(TraitSolverLangItem::Destruct) => {
|
||||
Some(SolverTraitLangItem::Destruct) => {
|
||||
G::consider_builtin_destruct_candidate(self, goal)
|
||||
}
|
||||
Some(TraitSolverLangItem::TransmuteTrait) => {
|
||||
Some(SolverTraitLangItem::TransmuteTrait) => {
|
||||
G::consider_builtin_transmute_candidate(self, goal)
|
||||
}
|
||||
Some(TraitSolverLangItem::BikeshedGuaranteedNoDrop) => {
|
||||
Some(SolverTraitLangItem::BikeshedGuaranteedNoDrop) => {
|
||||
G::consider_builtin_bikeshed_guaranteed_no_drop_candidate(self, goal)
|
||||
}
|
||||
_ => Err(NoSolution),
|
||||
|
|
@ -600,7 +600,7 @@ where
|
|||
|
||||
// There may be multiple unsize candidates for a trait with several supertraits:
|
||||
// `trait Foo: Bar<A> + Bar<B>` and `dyn Foo: Unsize<dyn Bar<_>>`
|
||||
if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Unsize) {
|
||||
if cx.is_trait_lang_item(trait_def_id, SolverTraitLangItem::Unsize) {
|
||||
candidates.extend(G::consider_structural_builtin_unsize_candidates(self, goal));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue