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:
The Miri Cronjob Bot 2025-08-24 05:02:05 +00:00
commit 005dc5cbdc
614 changed files with 10961 additions and 5595 deletions

View file

@ -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",
]

View file

@ -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 }
}
}

View file

@ -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
{

View file

@ -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" }

View file

@ -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

View file

@ -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 },
)
}
}

View file

@ -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 {

View file

@ -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 */

View file

@ -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"

View file

@ -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.)

View file

@ -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 })
}
}

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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 {

View file

@ -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;
}

View file

@ -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 {

View file

@ -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;
}
};

View file

@ -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
}

View file

@ -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,

View file

@ -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 {

View file

@ -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::*;

View file

@ -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

View file

@ -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,
}

View file

@ -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);
}

View file

@ -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>(

View file

@ -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.

View file

@ -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),

View file

@ -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 {

View file

@ -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);

View file

@ -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 }
}

View file

@ -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)

View file

@ -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;

View file

@ -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};

View file

@ -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(),
});
}
}

View file

@ -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};

View file

@ -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

View file

@ -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
}

View file

@ -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 {

View file

@ -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 })
}
}
}

View file

@ -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)?;

View file

@ -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;

View file

@ -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()
}
}

View file

@ -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" }

View 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(),
});
}
}

View file

@ -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>,

View file

@ -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;

View file

@ -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;

View file

@ -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(),

View file

@ -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) {

View file

@ -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};

View file

@ -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) => {

View file

@ -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),

View file

@ -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

View file

@ -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),

View file

@ -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,

View file

@ -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,
);

View file

@ -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

View file

@ -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)) }
}

View file

@ -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

View file

@ -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());

View file

@ -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);
}
}

View file

@ -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
};
}

View file

@ -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,

View file

@ -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>>,

View file

@ -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()
}

View file

@ -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>>,

View file

@ -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);

View file

@ -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;

View file

@ -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));

View file

@ -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}

View file

@ -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};

View file

@ -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),
});
}
}

View file

@ -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)
}
}
}

View file

@ -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" }

View file

@ -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 {

View file

@ -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" }

View file

@ -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>;

View file

@ -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

View file

@ -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)]

View file

@ -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;

View file

@ -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 {

View file

@ -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
}

View file

@ -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

View file

@ -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) }

View file

@ -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,

View file

@ -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};

View file

@ -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(),
}
}

View file

@ -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()

View file

@ -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(()),
}
}
}

View file

@ -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))
})
}

View file

@ -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));

View file

@ -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,

View file

@ -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 {

View file

@ -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;

View file

@ -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(

View file

@ -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.
//

View file

@ -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);

View file

@ -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,

View file

@ -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