Merge pull request #2595 from rust-lang/rustc-pull

Rustc pull update
This commit is contained in:
Tshepang Mbambo 2025-09-22 16:18:39 +02:00 committed by GitHub
commit 391a2ea868
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2078 changed files with 77161 additions and 38957 deletions

View file

@ -609,6 +609,7 @@ Shohei Wada <pc@wada314.jp>
Shotaro Yamada <sinkuu@sinkuu.xyz>
Shotaro Yamada <sinkuu@sinkuu.xyz> <sinkuu@users.noreply.github.com>
Shyam Sundar B <shyambaskaran@outlook.com>
Sidney Cammeresi <sac@cheesecake.org> <sac@readyset.io>
Simon Barber-Dueck <sbarberdueck@gmail.com> Simon BD <simon@server>
Simon Sapin <simon@exyr.org> <simon.sapin@exyr.org>
Simonas Kazlauskas <git@kazlauskas.me> Simonas Kazlauskas <github@kazlauskas.me>

View file

@ -568,7 +568,7 @@ checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
[[package]]
name = "clippy"
version = "0.1.91"
version = "0.1.92"
dependencies = [
"anstream",
"askama",
@ -595,7 +595,7 @@ dependencies = [
[[package]]
name = "clippy_config"
version = "0.1.91"
version = "0.1.92"
dependencies = [
"clippy_utils",
"itertools",
@ -618,7 +618,7 @@ dependencies = [
[[package]]
name = "clippy_lints"
version = "0.1.91"
version = "0.1.92"
dependencies = [
"arrayvec",
"cargo_metadata 0.18.1",
@ -649,7 +649,7 @@ dependencies = [
[[package]]
name = "clippy_utils"
version = "0.1.91"
version = "0.1.92"
dependencies = [
"arrayvec",
"itertools",
@ -937,23 +937,24 @@ dependencies = [
[[package]]
name = "cxx"
version = "1.0.168"
version = "1.0.185"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7aa144b12f11741f0dab5b4182896afad46faa0598b6a061f7b9d17a21837ba7"
checksum = "2f81de88da10862f22b5b3a60f18f6f42bbe7cb8faa24845dd7b1e4e22190e77"
dependencies = [
"cc",
"cxx-build",
"cxxbridge-cmd",
"cxxbridge-flags",
"cxxbridge-macro",
"foldhash",
"foldhash 0.2.0",
"link-cplusplus",
]
[[package]]
name = "cxx-build"
version = "1.0.168"
version = "1.0.185"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12d3cbb84fb003242941c231b45ca9417e786e66e94baa39584bd99df3a270b6"
checksum = "5edd58bf75c3fdfc80d79806403af626570662f7b6cc782a7fabe156166bd6d6"
dependencies = [
"cc",
"codespan-reporting",
@ -966,9 +967,9 @@ dependencies = [
[[package]]
name = "cxxbridge-cmd"
version = "1.0.168"
version = "1.0.185"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fa36b7b249d43f67a3f54bd65788e35e7afe64bbc671396387a48b3e8aaea94"
checksum = "fd46bf2b541a4e0c2d5abba76607379ee05d68e714868e3cb406dc8d591ce2d2"
dependencies = [
"clap",
"codespan-reporting",
@ -980,15 +981,15 @@ dependencies = [
[[package]]
name = "cxxbridge-flags"
version = "1.0.168"
version = "1.0.185"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77707c70f6563edc5429618ca34a07241b75ebab35bd01d46697c75d58f8ddfe"
checksum = "2c79b68f6a3a8f809d39b38ae8af61305a6113819b19b262643b9c21353b92d9"
[[package]]
name = "cxxbridge-macro"
version = "1.0.168"
version = "1.0.185"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ede6c0fb7e318f0a11799b86ee29dcf17b9be2960bd379a6c38e1a96a6010fff"
checksum = "862b7fdb048ff9ef0779a0d0a03affd09746c4c875543746b640756be9cff2af"
dependencies = [
"indexmap",
"proc-macro2",
@ -1051,7 +1052,7 @@ dependencies = [
[[package]]
name = "declare_clippy_lint"
version = "0.1.91"
version = "0.1.92"
[[package]]
name = "derive-where"
@ -1191,6 +1192,12 @@ version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8975ffdaa0ef3661bfe02dbdcc06c9f829dfafe6a3c474de366a8d5e44276921"
[[package]]
name = "dyn-clone"
version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005"
[[package]]
name = "either"
version = "1.15.0"
@ -1382,6 +1389,12 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "foldhash"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
[[package]]
name = "form_urlencoded"
version = "1.2.1"
@ -1458,9 +1471,9 @@ dependencies = [
[[package]]
name = "getopts"
version = "0.2.23"
version = "0.2.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1"
checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df"
dependencies = [
"unicode-width 0.2.1",
]
@ -1561,7 +1574,7 @@ checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
dependencies = [
"allocator-api2",
"equivalent",
"foldhash",
"foldhash 0.1.5",
"serde",
]
@ -2154,9 +2167,9 @@ dependencies = [
[[package]]
name = "link-cplusplus"
version = "1.0.10"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a6f6da007f968f9def0d65a05b187e2960183de70c160204ecfccf0ee330212"
checksum = "7f78c730aaa7d0b9336a299029ea49f9ee53b0ed06e9202e8cb7db9bae7b8c82"
dependencies = [
"cc",
]
@ -2167,6 +2180,7 @@ version = "0.1.0"
dependencies = [
"html5ever",
"regex",
"urlencoding",
]
[[package]]
@ -2346,11 +2360,11 @@ dependencies = [
[[package]]
name = "miow"
version = "0.6.0"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "359f76430b20a79f9e20e115b3428614e654f04fab314482fc0fda0ebd3c6044"
checksum = "536bfad37a309d62069485248eeaba1e8d9853aaf951caaeaed0585a95346f08"
dependencies = [
"windows-sys 0.48.0",
"windows-sys 0.60.2",
]
[[package]]
@ -3121,6 +3135,26 @@ dependencies = [
"thiserror 2.0.15",
]
[[package]]
name = "ref-cast"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf"
dependencies = [
"ref-cast-impl",
]
[[package]]
name = "ref-cast-impl"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.106",
]
[[package]]
name = "regex"
version = "1.11.1"
@ -3248,6 +3282,7 @@ dependencies = [
"rustc_driver_impl",
"rustc_public",
"rustc_public_bridge",
"rustc_windows_rc",
"tikv-jemalloc-sys",
]
@ -3623,6 +3658,7 @@ name = "rustc_driver"
version = "0.0.0"
dependencies = [
"rustc_driver_impl",
"rustc_windows_rc",
]
[[package]]
@ -4206,6 +4242,7 @@ name = "rustc_mir_transform"
version = "0.0.0"
dependencies = [
"either",
"hashbrown",
"itertools",
"rustc_abi",
"rustc_arena",
@ -4409,7 +4446,6 @@ dependencies = [
"rustc_middle",
"rustc_query_system",
"rustc_serialize",
"rustc_session",
"rustc_span",
"tracing",
]
@ -4575,6 +4611,7 @@ dependencies = [
"rustc_macros",
"rustc_serialize",
"rustc_span",
"schemars",
"serde",
"serde_derive",
"serde_json",
@ -4681,6 +4718,7 @@ dependencies = [
name = "rustc_type_ir"
version = "0.0.0"
dependencies = [
"arrayvec",
"bitflags",
"derive-where",
"ena",
@ -4718,6 +4756,13 @@ dependencies = [
"semver",
]
[[package]]
name = "rustc_windows_rc"
version = "0.0.0"
dependencies = [
"cc",
]
[[package]]
name = "rustdoc"
version = "0.0.0"
@ -4780,9 +4825,9 @@ dependencies = [
[[package]]
name = "rustfix"
version = "0.8.1"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81864b097046da5df3758fdc6e4822bbb70afa06317e8ca45ea1b51cb8c5e5a4"
checksum = "82fa69b198d894d84e23afde8e9ab2af4400b2cba20d6bf2b428a8b01c222c5a"
dependencies = [
"serde",
"serde_json",
@ -4890,6 +4935,31 @@ dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "schemars"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0"
dependencies = [
"dyn-clone",
"ref-cast",
"schemars_derive",
"serde",
"serde_json",
]
[[package]]
name = "schemars_derive"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33d020396d1d138dc19f1165df7545479dcd58d93810dc5d646a16e55abefa80"
dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals",
"syn 2.0.106",
]
[[package]]
name = "scoped-tls"
version = "1.0.1"
@ -4964,6 +5034,17 @@ dependencies = [
"syn 2.0.106",
]
[[package]]
name = "serde_derive_internals"
version = "0.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.106",
]
[[package]]
name = "serde_json"
version = "1.0.142"
@ -5518,11 +5599,10 @@ checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
[[package]]
name = "tracing"
version = "0.1.37"
version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
dependencies = [
"cfg-if",
"pin-project-lite",
"tracing-attributes",
"tracing-core",
@ -5825,6 +5905,12 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "urlencoding"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
[[package]]
name = "utf-8"
version = "0.7.6"
@ -5969,9 +6055,9 @@ dependencies = [
[[package]]
name = "wasm-component-ld"
version = "0.5.16"
version = "0.5.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14cd35d6cae91109a0ffd207b573cf3c741cab7e921dd376ea7aaf2c52a3408c"
checksum = "1c9208f87cac2332fd80dcf36d54e9163d3446e28301e0c6e424984425738984"
dependencies = [
"anyhow",
"clap",
@ -5979,9 +6065,9 @@ dependencies = [
"libc",
"tempfile",
"wasi-preview1-component-adapter-provider",
"wasmparser 0.237.0",
"wasmparser 0.239.0",
"wat",
"windows-sys 0.59.0",
"windows-sys 0.60.2",
"winsplit",
"wit-component",
"wit-parser",
@ -6006,24 +6092,24 @@ dependencies = [
[[package]]
name = "wasm-encoder"
version = "0.237.0"
version = "0.239.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efe92d1321afa53ffc88a57c497bb7330c3cf84c98ffdba4a4caf6a0684fad3c"
checksum = "5be00faa2b4950c76fe618c409d2c3ea5a3c9422013e079482d78544bb2d184c"
dependencies = [
"leb128fmt",
"wasmparser 0.237.0",
"wasmparser 0.239.0",
]
[[package]]
name = "wasm-metadata"
version = "0.237.0"
version = "0.239.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cc0b0a0c4f35ca6efa7a797671372915d4e9659dba2d59edc6fafc931d19997"
checksum = "20b3ec880a9ac69ccd92fbdbcf46ee833071cf09f82bb005b2327c7ae6025ae2"
dependencies = [
"anyhow",
"indexmap",
"wasm-encoder 0.237.0",
"wasmparser 0.237.0",
"wasm-encoder 0.239.0",
"wasmparser 0.239.0",
]
[[package]]
@ -6048,9 +6134,9 @@ dependencies = [
[[package]]
name = "wasmparser"
version = "0.237.0"
version = "0.239.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d2a40ca0d2bdf4b0bf36c13a737d0b2c58e4c8aaefe1c57f336dd75369ca250"
checksum = "8c9d90bb93e764f6beabf1d02028c70a2156a6583e63ac4218dd07ef733368b0"
dependencies = [
"bitflags",
"hashbrown",
@ -6061,22 +6147,22 @@ dependencies = [
[[package]]
name = "wast"
version = "237.0.0"
version = "239.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcf66f545acbd55082485cb9a6daab54579cb8628a027162253e8e9f5963c767"
checksum = "9139176fe8a2590e0fb174cdcaf373b224cb93c3dde08e4297c1361d2ba1ea5d"
dependencies = [
"bumpalo",
"leb128fmt",
"memchr",
"unicode-width 0.2.1",
"wasm-encoder 0.237.0",
"wasm-encoder 0.239.0",
]
[[package]]
name = "wat"
version = "1.237.0"
version = "1.239.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27975186f549e4b8d6878b627be732863883c72f7bf4dcf8f96e5f8242f73da9"
checksum = "3e1c941927d34709f255558166f8901a2005f8ab4a9650432e9281b7cc6f3b75"
dependencies = [
"wast",
]
@ -6299,15 +6385,6 @@ dependencies = [
"windows-link",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
@ -6335,21 +6412,6 @@ dependencies = [
"windows-targets 0.53.3",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc 0.48.5",
"windows_i686_gnu 0.48.5",
"windows_i686_msvc 0.48.5",
"windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc 0.48.5",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
@ -6392,12 +6454,6 @@ dependencies = [
"windows-link",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
@ -6410,12 +6466,6 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
@ -6428,12 +6478,6 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
@ -6458,12 +6502,6 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
@ -6476,12 +6514,6 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
@ -6494,12 +6526,6 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
@ -6512,12 +6538,6 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
@ -6565,9 +6585,9 @@ dependencies = [
[[package]]
name = "wit-component"
version = "0.237.0"
version = "0.239.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfb7674f76c10e82fe00b256a9d4ffb2b8d037d42ab8e9a83ebb3be35c9d0bf6"
checksum = "88a866b19dba2c94d706ec58c92a4c62ab63e482b4c935d2a085ac94caecb136"
dependencies = [
"anyhow",
"bitflags",
@ -6576,17 +6596,17 @@ dependencies = [
"serde",
"serde_derive",
"serde_json",
"wasm-encoder 0.237.0",
"wasm-encoder 0.239.0",
"wasm-metadata",
"wasmparser 0.237.0",
"wasmparser 0.239.0",
"wit-parser",
]
[[package]]
name = "wit-parser"
version = "0.237.0"
version = "0.239.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce2596a5bc7c24cc965b56ad6ff9e32394c4e401764f89620a888519c6e849ab"
checksum = "55c92c939d667b7bf0c6bf2d1f67196529758f99a2a45a3355cc56964fd5315d"
dependencies = [
"anyhow",
"id-arena",
@ -6597,7 +6617,7 @@ dependencies = [
"serde_derive",
"serde_json",
"unicode-xid",
"wasmparser 0.237.0",
"wasmparser 0.239.0",
]
[[package]]

View file

@ -1,3 +1,129 @@
Version 1.90.0 (2025-09-18)
===========================
<a id="1.90-Language"></a>
Language
--------
- [Split up the `unknown_or_malformed_diagnostic_attributes` lint](https://github.com/rust-lang/rust/pull/140717). This lint has been split up into four finer-grained lints, with `unknown_or_malformed_diagnostic_attributes` now being the lint group that contains these lints:
1. `unknown_diagnostic_attributes`: unknown to the current compiler
2. `misplaced_diagnostic_attributes`: placed on the wrong item
3. `malformed_diagnostic_attributes`: malformed attribute syntax or options
4. `malformed_diagnostic_format_literals`: malformed format string literal
- [Allow constants whose final value has references to mutable/external memory, but reject such constants as patterns](https://github.com/rust-lang/rust/pull/140942)
- [Allow volatile access to non-Rust memory, including address 0](https://github.com/rust-lang/rust/pull/141260)
<a id="1.90-Compiler"></a>
Compiler
--------
- [Use `lld` by default on `x86_64-unknown-linux-gnu`](https://github.com/rust-lang/rust/pull/140525).
- [Tier 3 `musl` targets now link dynamically by default](https://github.com/rust-lang/rust/pull/144410). Affected targets:
- `mips64-unknown-linux-muslabi64`
- `powerpc64-unknown-linux-musl`
- `powerpc-unknown-linux-musl`
- `powerpc-unknown-linux-muslspe`
- `riscv32gc-unknown-linux-musl`
- `s390x-unknown-linux-musl`
- `thumbv7neon-unknown-linux-musleabihf`
<a id="1.90-Platform-Support"></a>
Platform Support
----------------
- [Demote `x86_64-apple-darwin` to Tier 2 with host tools](https://github.com/rust-lang/rust/pull/145252)
Refer to Rust's [platform support page][platform-support-doc]
for more information on Rust's tiered platform support.
[platform-support-doc]: https://doc.rust-lang.org/rustc/platform-support.html
<a id="1.90-Libraries"></a>
Libraries
---------
- [Stabilize `u*::{checked,overflowing,saturating,wrapping}_sub_signed`](https://github.com/rust-lang/rust/issues/126043)
- [Allow comparisons between `CStr`, `CString`, and `Cow<CStr>`](https://github.com/rust-lang/rust/pull/137268)
- [Remove some unsized tuple impls since unsized tuples can't be constructed](https://github.com/rust-lang/rust/pull/138340)
- [Set `MSG_NOSIGNAL` for `UnixStream`](https://github.com/rust-lang/rust/pull/140005)
- [`proc_macro::Ident::new` now supports `$crate`.](https://github.com/rust-lang/rust/pull/141996)
- [Guarantee the pointer returned from `Thread::into_raw` has at least 8 bytes of alignment](https://github.com/rust-lang/rust/pull/143859)
<a id="1.90-Stabilized-APIs"></a>
Stabilized APIs
---------------
- [`u{n}::checked_sub_signed`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.checked_sub_signed)
- [`u{n}::overflowing_sub_signed`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.overflowing_sub_signed)
- [`u{n}::saturating_sub_signed`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.saturating_sub_signed)
- [`u{n}::wrapping_sub_signed`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.wrapping_sub_signed)
- [`impl Copy for IntErrorKind`](https://doc.rust-lang.org/stable/std/num/enum.IntErrorKind.html#impl-Copy-for-IntErrorKind)
- [`impl Hash for IntErrorKind`](https://doc.rust-lang.org/stable/std/num/enum.IntErrorKind.html#impl-Hash-for-IntErrorKind)
- [`impl PartialEq<&CStr> for CStr`](https://doc.rust-lang.org/stable/std/ffi/struct.CStr.html#impl-PartialEq%3C%26CStr%3E-for-CStr)
- [`impl PartialEq<CString> for CStr`](https://doc.rust-lang.org/stable/std/ffi/struct.CStr.html#impl-PartialEq%3CCString%3E-for-CStr)
- [`impl PartialEq<Cow<CStr>> for CStr`](https://doc.rust-lang.org/stable/std/ffi/struct.CStr.html#impl-PartialEq%3CCow%3C'_,+CStr%3E%3E-for-CStr)
- [`impl PartialEq<&CStr> for CString`](https://doc.rust-lang.org/stable/std/ffi/struct.CString.html#impl-PartialEq%3C%26CStr%3E-for-CString)
- [`impl PartialEq<CStr> for CString`](https://doc.rust-lang.org/stable/std/ffi/struct.CString.html#impl-PartialEq%3CCStr%3E-for-CString)
- [`impl PartialEq<Cow<CStr>> for CString`](https://doc.rust-lang.org/stable/std/ffi/struct.CString.html#impl-PartialEq%3CCow%3C'_,+CStr%3E%3E-for-CString)
- [`impl PartialEq<&CStr> for Cow<CStr>`](https://doc.rust-lang.org/stable/std/borrow/enum.Cow.html#impl-PartialEq%3C%26CStr%3E-for-Cow%3C'_,+CStr%3E)
- [`impl PartialEq<CStr> for Cow<CStr>`](https://doc.rust-lang.org/stable/std/borrow/enum.Cow.html#impl-PartialEq%3CCStr%3E-for-Cow%3C'_,+CStr%3E)
- [`impl PartialEq<CString> for Cow<CStr>`](https://doc.rust-lang.org/stable/std/borrow/enum.Cow.html#impl-PartialEq%3CCString%3E-for-Cow%3C'_,+CStr%3E)
These previously stable APIs are now stable in const contexts:
- [`<[T]>::reverse`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.reverse)
- [`f32::floor`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.floor)
- [`f32::ceil`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.ceil)
- [`f32::trunc`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.trunc)
- [`f32::fract`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.fract)
- [`f32::round`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.round)
- [`f32::round_ties_even`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.round_ties_even)
- [`f64::floor`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.floor)
- [`f64::ceil`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.ceil)
- [`f64::trunc`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.trunc)
- [`f64::fract`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.fract)
- [`f64::round`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.round)
- [`f64::round_ties_even`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.round_ties_even)
<a id="1.90-Cargo"></a>
Cargo
-----
- [Add `http.proxy-cainfo` config for proxy certs](https://github.com/rust-lang/cargo/pull/15374/)
- [Use `gix` for `cargo package`](https://github.com/rust-lang/cargo/pull/15534/)
- [feat(publish): Stabilize multi-package publishing](https://github.com/rust-lang/cargo/pull/15636/)
<a id="1.90-Rustdoc"></a>
Rustdoc
-----
- [Add ways to collapse all impl blocks](https://github.com/rust-lang/rust/pull/141663). Previously the "Summary" button and "-" keyboard shortcut would never collapse `impl` blocks, now they do when shift is held
- [Display unsafe attributes with `unsafe()` wrappers](https://github.com/rust-lang/rust/pull/143662)
<a id="1.90-Compatibility-Notes"></a>
Compatibility Notes
-------------------
- [Use `lld` by default on `x86_64-unknown-linux-gnu`](https://github.com/rust-lang/rust/pull/140525).
See also <https://blog.rust-lang.org/2025/09/01/rust-lld-on-1.90.0-stable/>.
- [Make `core::iter::Fuse`'s `Default` impl construct `I::default()` internally as promised in the docs instead of always being empty](https://github.com/rust-lang/rust/pull/140985)
- [Set `MSG_NOSIGNAL` for `UnixStream`](https://github.com/rust-lang/rust/pull/140005)
This may change program behavior but results in the same behavior as other primitives (e.g., stdout, network sockets).
Programs relying on signals to terminate them should update handling of sockets to handle errors on write by exiting.
- [On Unix `std::env::home_dir` will use the fallback if the `HOME` environment variable is empty](https://github.com/rust-lang/rust/pull/141840)
- We now [reject unsupported `extern "{abi}"`s consistently in all positions](https://github.com/rust-lang/rust/pull/142134). This primarily affects the use of implementing traits on an `extern "{abi}"` function pointer, like `extern "stdcall" fn()`, on a platform that doesn't support that, like aarch64-unknown-linux-gnu. Direct usage of these unsupported ABI strings by declaring or defining functions was already rejected, so this is only a change for consistency.
- [const-eval: error when initializing a static writes to that static](https://github.com/rust-lang/rust/pull/143084)
- [Check that the `proc_macro_derive` macro has correct arguments when applied to the crate root](https://github.com/rust-lang/rust/pull/143607)
Version 1.89.0 (2025-08-07)
==========================

View file

@ -325,6 +325,9 @@
# Defaults to the Python interpreter used to execute x.py.
#build.python = "python"
# The path to (or name of) the resource compiler executable to use on Windows.
#build.windows-rc = "rc.exe"
# The path to the REUSE executable to use. Note that REUSE is not required in
# most cases, as our tooling relies on a cached (and shrunk) copy of the
# REUSE output present in the git repository and in our source tarballs.
@ -859,6 +862,14 @@
# Trigger a `DebugBreak` after an internal compiler error during bootstrap on Windows
#rust.break-on-ice = true
# Set the number of threads for the compiler frontend used during compilation of Rust code (passed to `-Zthreads`).
# The valid options are:
# 0 - Set the number of threads according to the detected number of threads of the host system
# 1 - Use a single thread for compilation of Rust code (the default)
# N - Number of threads used for compilation of Rust code
#
#rust.parallel-frontend-threads = 1
# =============================================================================
# Distribution options
#

View file

@ -30,6 +30,12 @@ features = ['unprefixed_malloc_on_supported_platforms']
check_only = ['rustc_driver_impl/check_only']
jemalloc = ['dep:tikv-jemalloc-sys']
llvm = ['rustc_driver_impl/llvm']
llvm_enzyme = ['rustc_driver_impl/llvm_enzyme']
max_level_info = ['rustc_driver_impl/max_level_info']
rustc_randomized_layouts = ['rustc_driver_impl/rustc_randomized_layouts']
# tidy-alphabetical-end
[build-dependencies]
# tidy-alphabetical-start
rustc_windows_rc = { path = "../rustc_windows_rc" }
# tidy-alphabetical-end

View file

@ -1,4 +1,6 @@
use std::env;
use std::{env, path};
use rustc_windows_rc::{VersionInfoFileType, compile_windows_resource_file};
fn main() {
let target_os = env::var("CARGO_CFG_TARGET_OS");
@ -13,6 +15,18 @@ fn main() {
// Add a manifest file to rustc.exe.
fn set_windows_exe_options() {
set_windows_resource();
set_windows_manifest();
}
fn set_windows_resource() {
let stem = path::PathBuf::from("rustc_main_resource");
let file_description = "rustc";
let res_file = compile_windows_resource_file(&stem, file_description, VersionInfoFileType::App);
println!("cargo:rustc-link-arg={}", res_file.display());
}
fn set_windows_manifest() {
static WINDOWS_MANIFEST_FILE: &str = "Windows Manifest.xml";
let mut manifest = env::current_dir().unwrap();

View file

@ -2284,6 +2284,54 @@ pub struct FnSig {
pub span: Span,
}
impl FnSig {
/// Return a span encompassing the header, or where to insert it if empty.
pub fn header_span(&self) -> Span {
match self.header.ext {
Extern::Implicit(span) | Extern::Explicit(_, span) => {
return self.span.with_hi(span.hi());
}
Extern::None => {}
}
match self.header.safety {
Safety::Unsafe(span) | Safety::Safe(span) => return self.span.with_hi(span.hi()),
Safety::Default => {}
};
if let Some(coroutine_kind) = self.header.coroutine_kind {
return self.span.with_hi(coroutine_kind.span().hi());
}
if let Const::Yes(span) = self.header.constness {
return self.span.with_hi(span.hi());
}
self.span.shrink_to_lo()
}
/// The span of the header's safety, or where to insert it if empty.
pub fn safety_span(&self) -> Span {
match self.header.safety {
Safety::Unsafe(span) | Safety::Safe(span) => span,
Safety::Default => {
// Insert after the `coroutine_kind` if available.
if let Some(extern_span) = self.header.ext.span() {
return extern_span.shrink_to_lo();
}
// Insert right at the front of the signature.
self.header_span().shrink_to_hi()
}
}
}
/// The span of the header's extern, or where to insert it if empty.
pub fn extern_span(&self) -> Span {
self.header.ext.span().unwrap_or(self.safety_span().shrink_to_hi())
}
}
/// A constraint on an associated item.
///
/// ### Examples
@ -3526,6 +3574,13 @@ impl Extern {
None => Extern::Implicit(span),
}
}
pub fn span(self) -> Option<Span> {
match self {
Extern::None => None,
Extern::Implicit(span) | Extern::Explicit(_, span) => Some(span),
}
}
}
/// A function header.
@ -3534,12 +3589,12 @@ impl Extern {
/// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`).
#[derive(Clone, Copy, Encodable, Decodable, Debug, Walkable)]
pub struct FnHeader {
/// Whether this is `unsafe`, or has a default safety.
pub safety: Safety,
/// Whether this is `async`, `gen`, or nothing.
pub coroutine_kind: Option<CoroutineKind>,
/// The `const` keyword, if any
pub constness: Const,
/// Whether this is `async`, `gen`, or nothing.
pub coroutine_kind: Option<CoroutineKind>,
/// Whether this is `unsafe`, or has a default safety.
pub safety: Safety,
/// The `extern` keyword and corresponding ABI string, if any.
pub ext: Extern,
}
@ -3553,38 +3608,6 @@ impl FnHeader {
|| matches!(constness, Const::Yes(_))
|| !matches!(ext, Extern::None)
}
/// Return a span encompassing the header, or none if all options are default.
pub fn span(&self) -> Option<Span> {
fn append(a: &mut Option<Span>, b: Span) {
*a = match a {
None => Some(b),
Some(x) => Some(x.to(b)),
}
}
let mut full_span = None;
match self.safety {
Safety::Unsafe(span) | Safety::Safe(span) => append(&mut full_span, span),
Safety::Default => {}
};
if let Some(coroutine_kind) = self.coroutine_kind {
append(&mut full_span, coroutine_kind.span());
}
if let Const::Yes(span) = self.constness {
append(&mut full_span, span);
}
match self.ext {
Extern::Implicit(span) | Extern::Explicit(_, span) => append(&mut full_span, span),
Extern::None => {}
}
full_span
}
}
impl Default for FnHeader {

View file

@ -1536,7 +1536,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::LangItem::Range
}
}
(None, Some(..), Closed) => hir::LangItem::RangeToInclusive,
(None, Some(..), Closed) => {
if self.tcx.features().new_range() {
hir::LangItem::RangeToInclusiveCopy
} else {
hir::LangItem::RangeToInclusive
}
}
(Some(e1), Some(e2), Closed) => {
if self.tcx.features().new_range() {
hir::LangItem::RangeInclusiveCopy
@ -1560,13 +1566,26 @@ impl<'hir> LoweringContext<'_, 'hir> {
};
let fields = self.arena.alloc_from_iter(
e1.iter().map(|e| (sym::start, e)).chain(e2.iter().map(|e| (sym::end, e))).map(
|(s, e)| {
e1.iter()
.map(|e| (sym::start, e))
.chain(e2.iter().map(|e| {
(
if matches!(
lang_item,
hir::LangItem::RangeInclusiveCopy | hir::LangItem::RangeToInclusiveCopy
) {
sym::last
} else {
sym::end
},
e,
)
}))
.map(|(s, e)| {
let expr = self.lower_expr(e);
let ident = Ident::new(s, self.lower_span(e.span));
self.expr_field(ident, expr, e.span)
},
),
}),
);
hir::ExprKind::Struct(

View file

@ -5,7 +5,9 @@ use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err};
use rustc_hir::attrs::AttributeKind;
use rustc_hir::def::{DefKind, PerNS, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
use rustc_hir::{self as hir, HirId, LifetimeSource, PredicateOrigin, Target, find_attr};
use rustc_hir::{
self as hir, HirId, ImplItemImplKind, LifetimeSource, PredicateOrigin, Target, find_attr,
};
use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::span_bug;
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
@ -1117,20 +1119,31 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
};
let span = self.lower_span(i.span);
let item = hir::ImplItem {
owner_id: hir_id.expect_owner(),
ident: self.lower_ident(ident),
generics,
impl_kind: if is_in_trait_impl {
ImplItemImplKind::Trait {
defaultness,
trait_item_def_id: self
.resolver
.get_partial_res(i.id)
.and_then(|r| r.expect_full_res().opt_def_id())
.ok_or_else(|| {
self.dcx().span_delayed_bug(
span,
"could not resolve trait item being implemented",
)
}),
}
} else {
ImplItemImplKind::Inherent { vis_span: self.lower_span(i.vis.span) }
},
kind,
vis_span: self.lower_span(i.vis.span),
span: self.lower_span(i.span),
defaultness,
span,
has_delayed_lints: !self.delayed_lints.is_empty(),
trait_item_def_id: self
.resolver
.get_partial_res(i.id)
.map(|r| r.expect_full_res().opt_def_id())
.unwrap_or(None),
};
self.arena.alloc(item)
}

View file

@ -2101,17 +2101,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
{
return;
}
if self.tcx.features().more_maybe_bounds() {
return;
}
}
RelaxedBoundPolicy::Forbidden(reason) => {
if self.tcx.features().more_maybe_bounds() {
return;
}
match reason {
RelaxedBoundForbiddenReason::TraitObjectTy => {
if self.tcx.features().more_maybe_bounds() {
return;
}
self.dcx().span_err(
span,
"relaxed bounds are not permitted in trait object types",
@ -2119,6 +2116,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
return;
}
RelaxedBoundForbiddenReason::SuperTrait => {
if self.tcx.features().more_maybe_bounds() {
return;
}
let mut diag = self.dcx().struct_span_err(
span,
"relaxed bounds are not permitted in supertrait bounds",

View file

@ -57,8 +57,6 @@ ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetim
.label = {ast_passes_auto_super_lifetime}
.suggestion = remove the super traits or lifetime bounds
ast_passes_bad_c_variadic = defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block
.cannot_have = cannot have a body
.invalid = the invalid body
@ -66,6 +64,17 @@ ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block
ast_passes_bound_in_context = bounds on `type`s in {$ctx} have no effect
ast_passes_c_variadic_bad_extern = `...` is not supported for `extern "{$abi}"` functions
.label = `extern "{$abi}"` because of this
.help = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
ast_passes_c_variadic_must_be_unsafe =
functions with a C variable argument list must be unsafe
.suggestion = add the `unsafe` keyword to this definition
ast_passes_c_variadic_no_extern = `...` is not supported for non-extern functions
.help = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
ast_passes_const_and_c_variadic = functions cannot be both `const` and C-variadic
.const = `const` because of this
.variadic = C-variadic because of this
@ -84,6 +93,10 @@ ast_passes_const_without_body =
ast_passes_constraint_on_negative_bound =
associated type constraints not allowed on negative bounds
ast_passes_coroutine_and_c_variadic = functions cannot be both `{$coroutine_kind}` and C-variadic
.const = `{$coroutine_kind}` because of this
.variadic = C-variadic because of this
ast_passes_equality_in_where = equality constraints are not yet supported in `where` clauses
.label = not supported
.suggestion = if `{$ident}` is an associated type you're trying to set, use the associated type binding syntax
@ -201,6 +214,10 @@ ast_passes_match_arm_with_no_body =
.suggestion = add a body after the pattern
ast_passes_missing_unsafe_on_extern = extern blocks must be unsafe
.suggestion = needs `unsafe` before the extern keyword
ast_passes_missing_unsafe_on_extern_lint = extern blocks should be unsafe
.suggestion = needs `unsafe` before the extern keyword
ast_passes_module_nonascii = trying to load file for module `{$name}` with non-ascii identifier name
.help = consider using the `#[path]` attribute to specify filesystem path

View file

@ -492,7 +492,7 @@ impl<'a> AstValidator<'a> {
}
if !spans.is_empty() {
let header_span = sig.header.span().unwrap_or(sig.span.shrink_to_lo());
let header_span = sig.header_span();
let suggestion_span = header_span.shrink_to_hi().to(sig.decl.output.span());
let padding = if header_span.is_empty() { "" } else { " " };
@ -665,46 +665,68 @@ impl<'a> AstValidator<'a> {
/// - Non-const
/// - Either foreign, or free and `unsafe extern "C"` semantically
fn check_c_variadic_type(&self, fk: FnKind<'a>) {
let variadic_spans: Vec<_> = fk
.decl()
.inputs
.iter()
.filter(|arg| matches!(arg.ty.kind, TyKind::CVarArgs))
.map(|arg| arg.span)
.collect();
// `...` is already rejected when it is not the final parameter.
let variadic_param = match fk.decl().inputs.last() {
Some(param) if matches!(param.ty.kind, TyKind::CVarArgs) => param,
_ => return,
};
if variadic_spans.is_empty() {
return;
}
let FnKind::Fn(fn_ctxt, _, Fn { sig, .. }) = fk else {
// Unreachable because the parser already rejects `...` in closures.
unreachable!("C variable argument list cannot be used in closures")
};
if let Some(header) = fk.header()
&& let Const::Yes(const_span) = header.constness
{
let mut spans = variadic_spans.clone();
spans.push(const_span);
// C-variadics are not yet implemented in const evaluation.
if let Const::Yes(const_span) = sig.header.constness {
self.dcx().emit_err(errors::ConstAndCVariadic {
spans,
spans: vec![const_span, variadic_param.span],
const_span,
variadic_spans: variadic_spans.clone(),
variadic_span: variadic_param.span,
});
}
match (fk.ctxt(), fk.header()) {
(Some(FnCtxt::Foreign), _) => return,
(Some(FnCtxt::Free), Some(header)) => match header.ext {
Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }, _)
| Extern::Explicit(StrLit { symbol_unescaped: sym::C_dash_unwind, .. }, _)
| Extern::Implicit(_)
if matches!(header.safety, Safety::Unsafe(_)) =>
{
return;
}
_ => {}
},
_ => {}
};
if let Some(coroutine_kind) = sig.header.coroutine_kind {
self.dcx().emit_err(errors::CoroutineAndCVariadic {
spans: vec![coroutine_kind.span(), variadic_param.span],
coroutine_kind: coroutine_kind.as_str(),
coroutine_span: coroutine_kind.span(),
variadic_span: variadic_param.span,
});
}
self.dcx().emit_err(errors::BadCVariadic { span: variadic_spans });
match fn_ctxt {
FnCtxt::Foreign => return,
FnCtxt::Free | FnCtxt::Assoc(_) => match sig.header.ext {
Extern::Implicit(_) => {
if !matches!(sig.header.safety, Safety::Unsafe(_)) {
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
span: variadic_param.span,
unsafe_span: sig.safety_span(),
});
}
}
Extern::Explicit(StrLit { symbol_unescaped, .. }, _) => {
if !matches!(symbol_unescaped, sym::C | sym::C_dash_unwind) {
self.dcx().emit_err(errors::CVariadicBadExtern {
span: variadic_param.span,
abi: symbol_unescaped,
extern_span: sig.extern_span(),
});
}
if !matches!(sig.header.safety, Safety::Unsafe(_)) {
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
span: variadic_param.span,
unsafe_span: sig.safety_span(),
});
}
}
Extern::None => {
let err = errors::CVariadicNoExtern { span: variadic_param.span };
self.dcx().emit_err(err);
}
},
}
}
fn check_item_named(&self, ident: Ident, kind: &str) {
@ -1104,7 +1126,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
MISSING_UNSAFE_ON_EXTERN,
item.id,
item.span,
BuiltinLintDiag::MissingUnsafeOnExtern {
errors::MissingUnsafeOnExternLint {
suggestion: item.span.shrink_to_lo(),
},
);

View file

@ -319,10 +319,37 @@ pub(crate) struct ExternItemAscii {
}
#[derive(Diagnostic)]
#[diag(ast_passes_bad_c_variadic)]
pub(crate) struct BadCVariadic {
#[diag(ast_passes_c_variadic_no_extern)]
#[help]
pub(crate) struct CVariadicNoExtern {
#[primary_span]
pub span: Vec<Span>,
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_c_variadic_must_be_unsafe)]
pub(crate) struct CVariadicMustBeUnsafe {
#[primary_span]
pub span: Span,
#[suggestion(
ast_passes_suggestion,
applicability = "maybe-incorrect",
code = "unsafe ",
style = "verbose"
)]
pub unsafe_span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_c_variadic_bad_extern)]
#[help]
pub(crate) struct CVariadicBadExtern {
#[primary_span]
pub span: Span,
pub abi: Symbol,
#[label]
pub extern_span: Span,
}
#[derive(Diagnostic)]
@ -489,6 +516,13 @@ pub(crate) struct MissingUnsafeOnExtern {
pub span: Span,
}
#[derive(LintDiagnostic)]
#[diag(ast_passes_missing_unsafe_on_extern_lint)]
pub(crate) struct MissingUnsafeOnExternLint {
#[suggestion(code = "unsafe ", applicability = "machine-applicable")]
pub suggestion: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_fieldless_union)]
pub(crate) struct FieldlessUnion {
@ -656,7 +690,19 @@ pub(crate) struct ConstAndCVariadic {
#[label(ast_passes_const)]
pub const_span: Span,
#[label(ast_passes_variadic)]
pub variadic_spans: Vec<Span>,
pub variadic_span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_coroutine_and_c_variadic)]
pub(crate) struct CoroutineAndCVariadic {
#[primary_span]
pub spans: Vec<Span>,
pub coroutine_kind: &'static str,
#[label(ast_passes_const)]
pub coroutine_span: Span,
#[label(ast_passes_variadic)]
pub variadic_span: Span,
}
#[derive(Diagnostic)]

View file

@ -122,6 +122,14 @@ attr_parsing_null_on_export = `export_name` may not contain null characters
attr_parsing_null_on_link_section = `link_section` may not contain null characters
attr_parsing_null_on_objc_class = `objc::class!` may not contain null characters
attr_parsing_null_on_objc_selector = `objc::selector!` may not contain null characters
attr_parsing_objc_class_expected_string_literal = `objc::class!` expected a string literal
attr_parsing_objc_selector_expected_string_literal = `objc::selector!` expected a string literal
attr_parsing_repr_ident =
meta item in `repr` must be an identifier
@ -247,3 +255,7 @@ attr_parsing_raw_dylib_only_windows =
attr_parsing_whole_archive_needs_static =
linking modifier `whole-archive` is only compatible with `static` linking kind
attr_parsing_limit_invalid =
`limit` must be a non-negative integer
.label = {$error_str}

View file

@ -2,7 +2,10 @@ use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, SanitizerSet, UsedBy};
use rustc_session::parse::feature_err;
use super::prelude::*;
use crate::session_diagnostics::{NakedFunctionIncompatibleAttribute, NullOnExport};
use crate::session_diagnostics::{
NakedFunctionIncompatibleAttribute, NullOnExport, NullOnObjcClass, NullOnObjcSelector,
ObjcClassExpectedStringLiteral, ObjcSelectorExpectedStringLiteral,
};
pub(crate) struct OptimizeParser;
@ -150,6 +153,70 @@ impl<S: Stage> SingleAttributeParser<S> for ExportNameParser {
}
}
pub(crate) struct ObjcClassParser;
impl<S: Stage> SingleAttributeParser<S> for ObjcClassParser {
const PATH: &[rustc_span::Symbol] = &[sym::rustc_objc_class];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]);
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "ClassName");
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let Some(nv) = args.name_value() else {
cx.expected_name_value(cx.attr_span, None);
return None;
};
let Some(classname) = nv.value_as_str() else {
// `#[rustc_objc_class = ...]` is expected to be used as an implementatioin detail
// inside a standard library macro, but `cx.expected_string_literal` exposes too much.
// Use a custom error message instead.
cx.emit_err(ObjcClassExpectedStringLiteral { span: nv.value_span });
return None;
};
if classname.as_str().contains('\0') {
// `#[rustc_objc_class = ...]` will be converted to a null-terminated string,
// so it may not contain any null characters.
cx.emit_err(NullOnObjcClass { span: nv.value_span });
return None;
}
Some(AttributeKind::ObjcClass { classname, span: cx.attr_span })
}
}
pub(crate) struct ObjcSelectorParser;
impl<S: Stage> SingleAttributeParser<S> for ObjcSelectorParser {
const PATH: &[rustc_span::Symbol] = &[sym::rustc_objc_selector];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]);
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "methodName");
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let Some(nv) = args.name_value() else {
cx.expected_name_value(cx.attr_span, None);
return None;
};
let Some(methname) = nv.value_as_str() else {
// `#[rustc_objc_selector = ...]` is expected to be used as an implementatioin detail
// inside a standard library macro, but `cx.expected_string_literal` exposes too much.
// Use a custom error message instead.
cx.emit_err(ObjcSelectorExpectedStringLiteral { span: nv.value_span });
return None;
};
if methname.as_str().contains('\0') {
// `#[rustc_objc_selector = ...]` will be converted to a null-terminated string,
// so it may not contain any null characters.
cx.emit_err(NullOnObjcSelector { span: nv.value_span });
return None;
}
Some(AttributeKind::ObjcSelector { methname, span: cx.attr_span })
}
}
#[derive(Default)]
pub(crate) struct NakedParser {
span: Option<Span>,
@ -218,6 +285,7 @@ impl<S: Stage> AttributeParser<S> for NakedParser {
sym::rustc_std_internal_symbol,
// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity
sym::rustc_align,
sym::rustc_align_static,
// obviously compatible with self
sym::naked,
// documentation

View file

@ -1,6 +1,40 @@
use rustc_feature::AttributeType;
use std::num::IntErrorKind;
use rustc_hir::limit::Limit;
use super::prelude::*;
use crate::session_diagnostics::LimitInvalid;
impl<S: Stage> AcceptContext<'_, '_, S> {
fn parse_limit_int(&self, nv: &NameValueParser) -> Option<Limit> {
let Some(limit) = nv.value_as_str() else {
self.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
return None;
};
let error_str = match limit.as_str().parse() {
Ok(i) => return Some(Limit::new(i)),
Err(e) => match e.kind() {
IntErrorKind::PosOverflow => "`limit` is too large",
IntErrorKind::Empty => "`limit` must be a non-negative integer",
IntErrorKind::InvalidDigit => "not a valid integer",
IntErrorKind::NegOverflow => {
panic!(
"`limit` should never negatively overflow since we're parsing into a usize and we'd get Empty instead"
)
}
IntErrorKind::Zero => {
panic!("zero is a valid `limit` so should have returned Ok() when parsing")
}
kind => panic!("unimplemented IntErrorKind variant: {:?}", kind),
},
};
self.emit_err(LimitInvalid { span: self.attr_span, value_span: nv.value_span, error_str });
None
}
}
pub(crate) struct CrateNameParser;
@ -9,11 +43,7 @@ impl<S: Stage> SingleAttributeParser<S> for CrateNameParser {
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
const TYPE: AttributeType = AttributeType::CrateLevel;
// FIXME: crate name is allowed on all targets and ignored,
// even though it should only be valid on crates of course
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let ArgParser::NameValue(n) = args else {
@ -34,3 +64,122 @@ impl<S: Stage> SingleAttributeParser<S> for CrateNameParser {
})
}
}
pub(crate) struct RecursionLimitParser;
impl<S: Stage> SingleAttributeParser<S> for RecursionLimitParser {
const PATH: &[Symbol] = &[sym::recursion_limit];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute");
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let ArgParser::NameValue(nv) = args else {
cx.expected_name_value(cx.attr_span, None);
return None;
};
Some(AttributeKind::RecursionLimit {
limit: cx.parse_limit_int(nv)?,
attr_span: cx.attr_span,
limit_span: nv.value_span,
})
}
}
pub(crate) struct MoveSizeLimitParser;
impl<S: Stage> SingleAttributeParser<S> for MoveSizeLimitParser {
const PATH: &[Symbol] = &[sym::move_size_limit];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let ArgParser::NameValue(nv) = args else {
cx.expected_name_value(cx.attr_span, None);
return None;
};
Some(AttributeKind::MoveSizeLimit {
limit: cx.parse_limit_int(nv)?,
attr_span: cx.attr_span,
limit_span: nv.value_span,
})
}
}
pub(crate) struct TypeLengthLimitParser;
impl<S: Stage> SingleAttributeParser<S> for TypeLengthLimitParser {
const PATH: &[Symbol] = &[sym::type_length_limit];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let ArgParser::NameValue(nv) = args else {
cx.expected_name_value(cx.attr_span, None);
return None;
};
Some(AttributeKind::TypeLengthLimit {
limit: cx.parse_limit_int(nv)?,
attr_span: cx.attr_span,
limit_span: nv.value_span,
})
}
}
pub(crate) struct PatternComplexityLimitParser;
impl<S: Stage> SingleAttributeParser<S> for PatternComplexityLimitParser {
const PATH: &[Symbol] = &[sym::pattern_complexity_limit];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let ArgParser::NameValue(nv) = args else {
cx.expected_name_value(cx.attr_span, None);
return None;
};
Some(AttributeKind::PatternComplexityLimit {
limit: cx.parse_limit_int(nv)?,
attr_span: cx.attr_span,
limit_span: nv.value_span,
})
}
}
pub(crate) struct NoCoreParser;
impl<S: Stage> NoArgsAttributeParser<S> for NoCoreParser {
const PATH: &[Symbol] = &[sym::no_core];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoCore;
}
pub(crate) struct NoStdParser;
impl<S: Stage> NoArgsAttributeParser<S> for NoStdParser {
const PATH: &[Symbol] = &[sym::no_std];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoStd;
}
pub(crate) struct RustcCoherenceIsCoreParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcCoherenceIsCoreParser {
const PATH: &[Symbol] = &[sym::rustc_coherence_is_core];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcCoherenceIsCore;
}

View file

@ -1,3 +1,4 @@
use rustc_ast::AttrStyle;
use rustc_errors::DiagArgValue;
use rustc_hir::attrs::MacroUseArgs;
@ -133,3 +134,65 @@ impl<S: Stage> NoArgsAttributeParser<S> for AllowInternalUnsafeParser {
]);
const CREATE: fn(Span) -> AttributeKind = |span| AttributeKind::AllowInternalUnsafe(span);
}
pub(crate) struct MacroExportParser;
impl<S: Stage> SingleAttributeParser<S> for MacroExportParser {
const PATH: &[Symbol] = &[sym::macro_export];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const TEMPLATE: AttributeTemplate = template!(Word, List: &["local_inner_macros"]);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
Allow(Target::MacroDef),
Error(Target::WherePredicate),
Error(Target::Crate),
]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let suggestions = || {
<Self as SingleAttributeParser<S>>::TEMPLATE
.suggestions(AttrStyle::Inner, "macro_export")
};
let local_inner_macros = match args {
ArgParser::NoArgs => false,
ArgParser::List(list) => {
let Some(l) = list.single() else {
let span = cx.attr_span;
cx.emit_lint(
AttributeLintKind::InvalidMacroExportArguments {
suggestions: suggestions(),
},
span,
);
return None;
};
match l.meta_item().and_then(|i| i.path().word_sym()) {
Some(sym::local_inner_macros) => true,
_ => {
let span = cx.attr_span;
cx.emit_lint(
AttributeLintKind::InvalidMacroExportArguments {
suggestions: suggestions(),
},
span,
);
return None;
}
}
}
ArgParser::NameValue(_) => {
let span = cx.attr_span;
let suggestions = suggestions();
cx.emit_err(IllFormedAttributeInputLint {
num_suggestions: suggestions.len(),
suggestions: DiagArgValue::StrListSepByAnd(
suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
),
span,
});
return None;
}
};
Some(AttributeKind::MacroExport { span: cx.attr_span, local_inner_macros })
}
}

View file

@ -12,15 +12,11 @@
//! - [`CombineAttributeParser`](crate::attributes::CombineAttributeParser): makes it easy to implement an attribute which should combine the
//! contents of attributes, if an attribute appear multiple times in a list
//!
//! By default, attributes are allowed anywhere. When adding an attribute that should only be used
//! at the crate root, consider setting the `TYPE` in the parser trait to
//! [`AttributeType::CrateLevel`](rustc_feature::AttributeType::CrateLevel).
//!
//! Attributes should be added to `crate::context::ATTRIBUTE_PARSERS` to be parsed.
use std::marker::PhantomData;
use rustc_feature::{AttributeTemplate, AttributeType, template};
use rustc_feature::{AttributeTemplate, template};
use rustc_hir::attrs::AttributeKind;
use rustc_span::{Span, Symbol};
use thin_vec::ThinVec;
@ -89,11 +85,8 @@ pub(crate) trait AttributeParser<S: Stage>: Default + 'static {
///
/// If an attribute has this symbol, the `accept` function will be called on it.
const ATTRIBUTES: AcceptMapping<Self, S>;
const ALLOWED_TARGETS: AllowedTargets;
const TYPE: AttributeType = AttributeType::Normal;
/// The parser has gotten a chance to accept the attributes on an item,
/// here it can produce an attribute.
///
@ -135,8 +128,6 @@ pub(crate) trait SingleAttributeParser<S: Stage>: 'static {
/// The template this attribute parser should implement. Used for diagnostics.
const TEMPLATE: AttributeTemplate;
const TYPE: AttributeType = AttributeType::Normal;
/// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`]
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind>;
}
@ -183,8 +174,6 @@ impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S>
)];
const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
const TYPE: AttributeType = T::TYPE;
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
Some(self.1?.0)
}
@ -269,7 +258,6 @@ pub(crate) trait NoArgsAttributeParser<S: Stage>: 'static {
const PATH: &[Symbol];
const ON_DUPLICATE: OnDuplicate<S>;
const ALLOWED_TARGETS: AllowedTargets;
const TYPE: AttributeType = AttributeType::Normal;
/// Create the [`AttributeKind`] given attribute's [`Span`].
const CREATE: fn(Span) -> AttributeKind;
@ -289,7 +277,6 @@ impl<T: NoArgsAttributeParser<S>, S: Stage> SingleAttributeParser<S> for Without
const ON_DUPLICATE: OnDuplicate<S> = T::ON_DUPLICATE;
const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
const TEMPLATE: AttributeTemplate = template!(Word);
const TYPE: AttributeType = T::TYPE;
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
if let Err(span) = args.no_args() {
@ -323,8 +310,6 @@ pub(crate) trait CombineAttributeParser<S: Stage>: 'static {
/// The template this attribute parser should implement. Used for diagnostics.
const TEMPLATE: AttributeTemplate;
const TYPE: AttributeType = AttributeType::Normal;
/// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`]
fn extend<'c>(
cx: &'c mut AcceptContext<'_, '_, S>,
@ -360,7 +345,6 @@ impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S
group.items.extend(T::extend(cx, args))
})];
const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
const TYPE: AttributeType = T::TYPE;
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
if let Some(first_span) = self.first_span {

View file

@ -1,7 +1,6 @@
// templates
// data structures
#[doc(hidden)]
pub(super) use rustc_feature::{AttributeTemplate, template};
// data structures
#[doc(hidden)]
pub(super) use rustc_hir::attrs::AttributeKind;
#[doc(hidden)]

View file

@ -331,3 +331,30 @@ impl<S: Stage> AttributeParser<S> for AlignParser {
Some(AttributeKind::Align { align, span })
}
}
#[derive(Default)]
pub(crate) struct AlignStaticParser(AlignParser);
impl AlignStaticParser {
const PATH: &'static [Symbol] = &[sym::rustc_align_static];
const TEMPLATE: AttributeTemplate = AlignParser::TEMPLATE;
fn parse<'c, S: Stage>(
&mut self,
cx: &'c mut AcceptContext<'_, '_, S>,
args: &'c ArgParser<'_>,
) {
self.0.parse(cx, args)
}
}
impl<S: Stage> AttributeParser<S> for AlignStaticParser {
const ATTRIBUTES: AcceptMapping<Self, S> = &[(Self::PATH, Self::TEMPLATE, Self::parse)];
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Static), Allow(Target::ForeignStatic)]);
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
let (align, span) = self.0.0?;
Some(AttributeKind::Align { align, span })
}
}

View file

@ -1,7 +1,5 @@
use std::mem;
use rustc_feature::AttributeType;
use super::prelude::*;
use crate::attributes::{
AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser,
@ -151,15 +149,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for AllowIncoherentImplParser {
const CREATE: fn(Span) -> AttributeKind = AttributeKind::AllowIncoherentImpl;
}
pub(crate) struct CoherenceIsCoreParser;
impl<S: Stage> NoArgsAttributeParser<S> for CoherenceIsCoreParser {
const PATH: &[Symbol] = &[sym::rustc_coherence_is_core];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const TYPE: AttributeType = AttributeType::CrateLevel;
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CoherenceIsCore;
}
pub(crate) struct FundamentalParser;
impl<S: Stage> NoArgsAttributeParser<S> for FundamentalParser {
const PATH: &[Symbol] = &[sym::fundamental];

View file

@ -6,7 +6,7 @@ use std::sync::LazyLock;
use private::Sealed;
use rustc_ast::{AttrStyle, CRATE_NODE_ID, MetaItemLit, NodeId};
use rustc_errors::{Diag, Diagnostic, Level};
use rustc_feature::{AttributeTemplate, AttributeType};
use rustc_feature::AttributeTemplate;
use rustc_hir::attrs::AttributeKind;
use rustc_hir::lints::{AttributeLint, AttributeLintKind};
use rustc_hir::{AttrPath, CRATE_HIR_ID, HirId};
@ -20,11 +20,14 @@ use crate::attributes::allow_unstable::{
use crate::attributes::body::CoroutineParser;
use crate::attributes::codegen_attrs::{
ColdParser, CoverageParser, ExportNameParser, ForceTargetFeatureParser, NakedParser,
NoMangleParser, OptimizeParser, SanitizeParser, TargetFeatureParser, TrackCallerParser,
UsedParser,
NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser, SanitizeParser,
TargetFeatureParser, TrackCallerParser, UsedParser,
};
use crate::attributes::confusables::ConfusablesParser;
use crate::attributes::crate_level::CrateNameParser;
use crate::attributes::crate_level::{
CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoStdParser, PatternComplexityLimitParser,
RecursionLimitParser, RustcCoherenceIsCoreParser, TypeLengthLimitParser,
};
use crate::attributes::deprecation::DeprecationParser;
use crate::attributes::dummy::DummyParser;
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
@ -37,7 +40,7 @@ use crate::attributes::lint_helpers::{
};
use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
use crate::attributes::macro_attrs::{
AllowInternalUnsafeParser, MacroEscapeParser, MacroUseParser,
AllowInternalUnsafeParser, MacroEscapeParser, MacroExportParser, MacroUseParser,
};
use crate::attributes::must_use::MustUseParser;
use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
@ -47,7 +50,7 @@ use crate::attributes::proc_macro_attrs::{
ProcMacroAttributeParser, ProcMacroDeriveParser, ProcMacroParser, RustcBuiltinMacroParser,
};
use crate::attributes::prototype::CustomMirParser;
use crate::attributes::repr::{AlignParser, ReprParser};
use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser};
use crate::attributes::rustc_internal::{
RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart,
RustcObjectLifetimeDefaultParser,
@ -58,10 +61,10 @@ use crate::attributes::stability::{
};
use crate::attributes::test_attrs::{IgnoreParser, ShouldPanicParser};
use crate::attributes::traits::{
AllowIncoherentImplParser, CoherenceIsCoreParser, CoinductiveParser, ConstTraitParser,
DenyExplicitImplParser, DoNotImplementViaObjectParser, FundamentalParser, MarkerParser,
ParenSugarParser, PointeeParser, SkipDuringMethodDispatchParser, SpecializationTraitParser,
TypeConstParser, UnsafeSpecializationMarkerParser,
AllowIncoherentImplParser, CoinductiveParser, ConstTraitParser, DenyExplicitImplParser,
DoNotImplementViaObjectParser, FundamentalParser, MarkerParser, ParenSugarParser,
PointeeParser, SkipDuringMethodDispatchParser, SpecializationTraitParser, TypeConstParser,
UnsafeSpecializationMarkerParser,
};
use crate::attributes::transparency::TransparencyParser;
use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
@ -80,7 +83,6 @@ pub(super) struct GroupTypeInnerAccept<S: Stage> {
pub(super) template: AttributeTemplate,
pub(super) accept_fn: AcceptFn<S>,
pub(super) allowed_targets: AllowedTargets,
pub(super) attribute_type: AttributeType,
}
type AcceptFn<S> =
@ -130,7 +132,6 @@ macro_rules! attribute_parsers {
})
}),
allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS,
attribute_type: <$names as crate::attributes::AttributeParser<$stage>>::TYPE,
});
}
@ -149,6 +150,7 @@ attribute_parsers!(
pub(crate) static ATTRIBUTE_PARSERS = [
// tidy-alphabetical-start
AlignParser,
AlignStaticParser,
BodyStabilityParser,
ConfusablesParser,
ConstStabilityParser,
@ -181,10 +183,16 @@ attribute_parsers!(
Single<LinkOrdinalParser>,
Single<LinkSectionParser>,
Single<LinkageParser>,
Single<MacroExportParser>,
Single<MoveSizeLimitParser>,
Single<MustUseParser>,
Single<ObjcClassParser>,
Single<ObjcSelectorParser>,
Single<OptimizeParser>,
Single<PathAttributeParser>,
Single<PatternComplexityLimitParser>,
Single<ProcMacroDeriveParser>,
Single<RecursionLimitParser>,
Single<RustcBuiltinMacroParser>,
Single<RustcForceInlineParser>,
Single<RustcLayoutScalarValidRangeEnd>,
@ -194,11 +202,11 @@ attribute_parsers!(
Single<ShouldPanicParser>,
Single<SkipDuringMethodDispatchParser>,
Single<TransparencyParser>,
Single<TypeLengthLimitParser>,
Single<WithoutArgs<AllowIncoherentImplParser>>,
Single<WithoutArgs<AllowInternalUnsafeParser>>,
Single<WithoutArgs<AsPtrParser>>,
Single<WithoutArgs<AutomaticallyDerivedParser>>,
Single<WithoutArgs<CoherenceIsCoreParser>>,
Single<WithoutArgs<CoinductiveParser>>,
Single<WithoutArgs<ColdParser>>,
Single<WithoutArgs<ConstContinueParser>>,
@ -215,8 +223,10 @@ attribute_parsers!(
Single<WithoutArgs<MacroEscapeParser>>,
Single<WithoutArgs<MarkerParser>>,
Single<WithoutArgs<MayDangleParser>>,
Single<WithoutArgs<NoCoreParser>>,
Single<WithoutArgs<NoImplicitPreludeParser>>,
Single<WithoutArgs<NoMangleParser>>,
Single<WithoutArgs<NoStdParser>>,
Single<WithoutArgs<NonExhaustiveParser>>,
Single<WithoutArgs<ParenSugarParser>>,
Single<WithoutArgs<PassByValueParser>>,
@ -224,6 +234,7 @@ attribute_parsers!(
Single<WithoutArgs<ProcMacroAttributeParser>>,
Single<WithoutArgs<ProcMacroParser>>,
Single<WithoutArgs<PubTransparentParser>>,
Single<WithoutArgs<RustcCoherenceIsCoreParser>>,
Single<WithoutArgs<SpecializationTraitParser>>,
Single<WithoutArgs<StdInternalSymbolParser>>,
Single<WithoutArgs<TrackCallerParser>>,
@ -346,7 +357,10 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
/// must be delayed until after HIR is built. This method will take care of the details of
/// that.
pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) {
if matches!(self.stage.should_emit(), ShouldEmit::Nothing) {
if !matches!(
self.stage.should_emit(),
ShouldEmit::ErrorsAndLints | ShouldEmit::EarlyFatal { also_emit_lints: true }
) {
return;
}
let id = self.target_id;
@ -670,20 +684,20 @@ pub enum ShouldEmit {
///
/// Only relevant when early parsing, in late parsing equivalent to `ErrorsAndLints`.
/// Late parsing is never fatal, and instead tries to emit as many diagnostics as possible.
EarlyFatal,
EarlyFatal { also_emit_lints: bool },
/// The operation will emit errors and lints.
/// This is usually what you need.
ErrorsAndLints,
/// The operation will emit *not* errors and lints.
/// Use this if you are *sure* that this operation will be called at a different time with `ShouldEmit::Emit`.
/// Use this if you are *sure* that this operation will be called at a different time with `ShouldEmit::ErrorsAndLints`.
Nothing,
}
impl ShouldEmit {
pub(crate) fn emit_err(&self, diag: Diag<'_>) -> ErrorGuaranteed {
match self {
ShouldEmit::EarlyFatal if diag.level() == Level::DelayedBug => diag.emit(),
ShouldEmit::EarlyFatal => diag.upgrade_to_fatal().emit(),
ShouldEmit::EarlyFatal { .. } if diag.level() == Level::DelayedBug => diag.emit(),
ShouldEmit::EarlyFatal { .. } => diag.upgrade_to_fatal().emit(),
ShouldEmit::ErrorsAndLints => diag.emit(),
ShouldEmit::Nothing => diag.delay_as_bug(),
}

View file

@ -272,7 +272,6 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
(accept.accept_fn)(&mut cx, args);
if !matches!(cx.stage.should_emit(), ShouldEmit::Nothing) {
Self::check_type(accept.attribute_type, target, &mut cx);
Self::check_target(&accept.allowed_targets, target, &mut cx);
}
}

View file

@ -31,6 +31,18 @@ pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<L::Id>, lint_emi
},
);
}
AttributeLintKind::InvalidMacroExportArguments { suggestions } => lint_emitter
.emit_node_span_lint(
rustc_session::lint::builtin::INVALID_MACRO_EXPORT_ARGUMENTS,
*id,
*span,
session_diagnostics::IllFormedAttributeInput {
num_suggestions: suggestions.len(),
suggestions: DiagArgValue::StrListSepByAnd(
suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
),
},
),
AttributeLintKind::EmptyAttribute { first_span } => lint_emitter.emit_node_span_lint(
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
*id,

View file

@ -459,6 +459,34 @@ pub(crate) struct NullOnLinkSection {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_null_on_objc_class)]
pub(crate) struct NullOnObjcClass {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_null_on_objc_selector)]
pub(crate) struct NullOnObjcSelector {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_objc_class_expected_string_literal)]
pub(crate) struct ObjcClassExpectedStringLiteral {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_objc_selector_expected_string_literal)]
pub(crate) struct ObjcSelectorExpectedStringLiteral {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_stability_outside_std, code = E0734)]
pub(crate) struct StabilityOutsideStd {
@ -930,3 +958,13 @@ pub(crate) struct ImportNameTypeRaw {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_limit_invalid)]
pub(crate) struct LimitInvalid<'a> {
#[primary_span]
pub span: Span,
#[label]
pub value_span: Span,
pub error_str: &'a str,
}

View file

@ -2,7 +2,7 @@ use std::borrow::Cow;
use rustc_ast::AttrStyle;
use rustc_errors::DiagArgValue;
use rustc_feature::{AttributeType, Features};
use rustc_feature::Features;
use rustc_hir::lints::AttributeLintKind;
use rustc_hir::{MethodKind, Target};
@ -14,6 +14,11 @@ use crate::session_diagnostics::InvalidTarget;
pub(crate) enum AllowedTargets {
AllowList(&'static [Policy]),
AllowListWarnRest(&'static [Policy]),
/// Special, and not the same as `AllowList(&[Allow(Target::Crate)])`.
/// For crate-level attributes we emit a specific set of lints to warn
/// people about accidentally not using them on the crate.
/// Only use this for attributes that are *exclusively* valid at the crate level.
CrateLevel,
}
pub(crate) enum AllowedResult {
@ -43,6 +48,7 @@ impl AllowedTargets {
AllowedResult::Warn
}
}
AllowedTargets::CrateLevel => AllowedResult::Allowed,
}
}
@ -50,6 +56,7 @@ impl AllowedTargets {
match self {
AllowedTargets::AllowList(list) => list,
AllowedTargets::AllowListWarnRest(list) => list,
AllowedTargets::CrateLevel => ALL_TARGETS,
}
.iter()
.filter_map(|target| match target {
@ -74,6 +81,8 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
target: Target,
cx: &mut AcceptContext<'_, 'sess, S>,
) {
Self::check_type(matches!(allowed_targets, AllowedTargets::CrateLevel), target, cx);
match allowed_targets.is_allowed(target) {
AllowedResult::Allowed => {}
AllowedResult::Warn => {
@ -109,7 +118,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
}
pub(crate) fn check_type(
attribute_type: AttributeType,
crate_level: bool,
target: Target,
cx: &mut AcceptContext<'_, 'sess, S>,
) {
@ -119,7 +128,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
return;
}
if attribute_type != AttributeType::CrateLevel {
if !crate_level {
return;
}

View file

@ -438,7 +438,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
let elaborated_args =
std::iter::zip(*args, &generics.own_params).map(|(arg, param)| {
if let Some(ty::Dynamic(obj, _, ty::Dyn)) = arg.as_type().map(Ty::kind) {
if let Some(ty::Dynamic(obj, _)) = arg.as_type().map(Ty::kind) {
let default = tcx.object_lifetime_default(param.def_id);
let re_static = tcx.lifetimes.re_static;
@ -464,7 +464,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
has_dyn = true;
Ty::new_dynamic(tcx, obj, implied_region, ty::Dyn).into()
Ty::new_dynamic(tcx, obj, implied_region).into()
} else {
arg
}

View file

@ -716,7 +716,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
return (false, false, None);
};
let implemented_trait_item = self.infcx.tcx.associated_item(my_def).trait_item_def_id;
let implemented_trait_item = self.infcx.tcx.trait_item_of(my_def);
(
true,

View file

@ -166,13 +166,9 @@ impl RegionTracker {
}
}
/// Determine if the tracked universes of the two SCCs are compatible.
pub(crate) fn universe_compatible_with(&self, other: Self) -> bool {
// HACK: We first check whether we can name the highest existential universe
// of `other`. This only exists to avoid errors in case that scc already
// depends on a placeholder it cannot name itself.
self.max_nameable_universe().can_name(other.max_nameable_universe())
|| other.reachable_placeholders.can_be_named_by(self.max_nameable_universe())
/// Determine if we can name all the placeholders in `other`.
pub(crate) fn can_name_all_placeholders(&self, other: Self) -> bool {
other.reachable_placeholders.can_be_named_by(self.max_nameable_universe.0)
}
/// If this SCC reaches a placeholder it can't name, return it.

View file

@ -1557,9 +1557,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
);
}
&(Rvalue::Len(place) | Rvalue::Discriminant(place)) => {
&Rvalue::Discriminant(place) => {
let af = match *rvalue {
Rvalue::Len(..) => Some(ArtificialField::ArrayLength),
Rvalue::Discriminant(..) => None,
_ => unreachable!(),
};
@ -1904,7 +1903,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
| ty::Slice(_)
| ty::FnDef(_, _)
| ty::FnPtr(..)
| ty::Dynamic(_, _, _)
| ty::Dynamic(_, _)
| ty::Closure(_, _)
| ty::CoroutineClosure(_, _)
| ty::Coroutine(_, _)
@ -1950,7 +1949,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
| ty::Ref(_, _, _)
| ty::FnDef(_, _)
| ty::FnPtr(..)
| ty::Dynamic(_, _, _)
| ty::Dynamic(_, _)
| ty::CoroutineWitness(..)
| ty::Never
| ty::UnsafeBinder(_)

View file

@ -306,16 +306,11 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
self.consume_operand(location, op);
}
&(Rvalue::Len(place) | Rvalue::Discriminant(place)) => {
let af = match rvalue {
Rvalue::Len(..) => Some(ArtificialField::ArrayLength),
Rvalue::Discriminant(..) => None,
_ => unreachable!(),
};
&Rvalue::Discriminant(place) => {
self.access_place(
location,
place,
(Shallow(af), Read(ReadKind::Copy)),
(Shallow(None), Read(ReadKind::Copy)),
LocalMutationIsAllowed::No,
);
}

View file

@ -571,11 +571,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
}
/// Returns `true` if all the elements in the value of `scc_b` are nameable
/// Returns `true` if all the placeholders in the value of `scc_b` are nameable
/// in `scc_a`. Used during constraint propagation, and only once
/// the value of `scc_b` has been computed.
fn universe_compatible(&self, scc_b: ConstraintSccIndex, scc_a: ConstraintSccIndex) -> bool {
self.scc_annotations[scc_a].universe_compatible_with(self.scc_annotations[scc_b])
fn can_name_all_placeholders(
&self,
scc_a: ConstraintSccIndex,
scc_b: ConstraintSccIndex,
) -> bool {
self.scc_annotations[scc_a].can_name_all_placeholders(self.scc_annotations[scc_b])
}
/// Once regions have been propagated, this method is used to see
@ -615,7 +619,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
// Type-test failed. Report the error.
let erased_generic_kind = infcx.tcx.erase_regions(type_test.generic_kind);
let erased_generic_kind = infcx.tcx.erase_and_anonymize_regions(type_test.generic_kind);
// Skip duplicate-ish errors.
if deduplicate_errors.insert((
@ -964,16 +968,22 @@ impl<'tcx> RegionInferenceContext<'tcx> {
return true;
}
let fr_static = self.universal_regions().fr_static;
// If we are checking that `'sup: 'sub`, and `'sub` contains
// some placeholder that `'sup` cannot name, then this is only
// true if `'sup` outlives static.
if !self.universe_compatible(sub_region_scc, sup_region_scc) {
//
// Avoid infinite recursion if `sub_region` is already `'static`
if sub_region != fr_static
&& !self.can_name_all_placeholders(sup_region_scc, sub_region_scc)
{
debug!(
"sub universe `{sub_region_scc:?}` is not nameable \
by super `{sup_region_scc:?}`, promoting to static",
);
return self.eval_outlives(sup_region, self.universal_regions().fr_static);
return self.eval_outlives(sup_region, fr_static);
}
// Both the `sub_region` and `sup_region` consist of the union

View file

@ -341,7 +341,7 @@ fn compute_concrete_types_from_defining_uses<'tcx>(
//
// FIXME(-Znext-solver): This isn't necessary after all. We can remove this check again.
if let Some((prev_decl_key, prev_span)) = decls_modulo_regions.insert(
rcx.infcx.tcx.erase_regions(opaque_type_key),
rcx.infcx.tcx.erase_and_anonymize_regions(opaque_type_key),
(opaque_type_key, hidden_type.span),
) && let Some((arg1, arg2)) = std::iter::zip(
prev_decl_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg),

View file

@ -230,8 +230,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
location: impl NormalizeLocation,
) -> Ty<'tcx> {
let tcx = self.tcx();
let body = self.body;
let cause = ObligationCause::misc(
location.to_locations().span(body),
body.source.def_id().expect_local(),
);
if self.infcx.next_trait_solver() {
let body = self.body;
let param_env = self.infcx.param_env;
// FIXME: Make this into a real type op?
self.fully_perform_op(
@ -241,10 +247,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|ocx| {
let structurally_normalize = |ty| {
ocx.structurally_normalize_ty(
&ObligationCause::misc(
location.to_locations().span(body),
body.source.def_id().expect_local(),
),
&cause,
param_env,
ty,
)
@ -253,6 +256,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let tail = tcx.struct_tail_raw(
ty,
&cause,
structurally_normalize,
|| {},
);
@ -265,7 +269,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
.unwrap_or_else(|guar| Ty::new_error(tcx, guar))
} else {
let mut normalize = |ty| self.normalize(ty, location);
let tail = tcx.struct_tail_raw(ty, &mut normalize, || {});
let tail = tcx.struct_tail_raw(ty, &cause, &mut normalize, || {});
normalize(tail)
}
}

View file

@ -1487,9 +1487,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
unsize_to: None,
},
);
} else if let ty::Dynamic(src_tty, _src_lt, ty::Dyn) =
} else if let ty::Dynamic(src_tty, _src_lt) =
*self.struct_tail(src.ty, location).kind()
&& let ty::Dynamic(dst_tty, dst_lt, ty::Dyn) =
&& let ty::Dynamic(dst_tty, dst_lt) =
*self.struct_tail(dst.ty, location).kind()
&& src_tty.principal().is_some()
&& dst_tty.principal().is_some()
@ -1511,7 +1511,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
// FIXME: Once we disallow casting `*const dyn Trait + 'short`
// to `*const dyn Trait + 'long`, then this can just be `src_lt`.
dst_lt,
ty::Dyn,
);
let dst_obj = Ty::new_dynamic(
tcx,
@ -1519,7 +1518,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
&dst_tty.without_auto_traits().collect::<Vec<_>>(),
),
dst_lt,
ty::Dyn,
);
debug!(?src_tty, ?dst_tty, ?src_obj, ?dst_obj);
@ -1631,7 +1629,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
| Rvalue::BinaryOp(..)
| Rvalue::RawPtr(..)
| Rvalue::ThreadLocalRef(..)
| Rvalue::Len(..)
| Rvalue::Discriminant(..)
| Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => {}
}
@ -1892,7 +1889,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
if is_diverging {
// The signature in this call can reference region variables,
// so erase them before calling a query.
let output_ty = self.tcx().erase_regions(sig.output());
let output_ty = self.tcx().erase_and_anonymize_regions(sig.output());
if !output_ty
.is_privately_uninhabited(self.tcx(), self.infcx.typing_env(self.infcx.param_env))
{
@ -1986,7 +1983,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let op_arg_ty = self.normalize(op_arg_ty, term_location);
let category = if call_source.from_hir_call() {
ConstraintCategory::CallArgument(Some(self.infcx.tcx.erase_regions(func_ty)))
ConstraintCategory::CallArgument(Some(
self.infcx.tcx.erase_and_anonymize_regions(func_ty),
))
} else {
ConstraintCategory::Boring
};
@ -2120,7 +2119,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// Erase the regions from `ty` to get a global type. The
// `Sized` bound in no way depends on precise regions, so this
// shouldn't affect `is_sized`.
let erased_ty = tcx.erase_regions(ty);
let erased_ty = tcx.erase_and_anonymize_regions(ty);
// FIXME(#132279): Using `Ty::is_sized` causes us to incorrectly handle opaques here.
if !erased_ty.is_sized(tcx, self.infcx.typing_env(self.infcx.param_env)) {
// in current MIR construction, all non-control-flow rvalue
@ -2199,7 +2198,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
| Rvalue::Repeat(..)
| Rvalue::Ref(..)
| Rvalue::RawPtr(..)
| Rvalue::Len(..)
| Rvalue::Cast(..)
| Rvalue::ShallowInitBox(..)
| Rvalue::BinaryOp(..)

View file

@ -33,3 +33,8 @@ smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
thin-vec = "0.2.12"
tracing = "0.1"
# tidy-alphabetical-end
[features]
# tidy-alphabetical-start
llvm_enzyme = []
# tidy-alphabetical-end

View file

@ -64,6 +64,11 @@ builtin_macros_autodiff_ty_activity = {$act} can not be used for this type
builtin_macros_autodiff_unknown_activity = did not recognize Activity: `{$act}`
builtin_macros_autodiff_width = autodiff width must fit u32, but is {$width}
builtin_macros_avoid_att_syntax = avoid using `.att_syntax`, prefer using `options(att_syntax)` instead
builtin_macros_avoid_intel_syntax = avoid using `.intel_syntax`, Intel syntax is the default
builtin_macros_bad_derive_target = `derive` may only be applied to `struct`s, `enum`s and `union`s
.label = not applicable here
.label2 = not a `struct`, `enum` or `union`
@ -138,6 +143,8 @@ builtin_macros_derive_path_args_list = traits in `#[derive(...)]` don't accept a
builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept values
.suggestion = remove the value
builtin_macros_duplicate_macro_attribute = duplicated attribute
builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time
.cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead
.custom = use `std::env::var({$var_expr})` to read the variable at run time
@ -231,6 +238,8 @@ builtin_macros_derive_from_wrong_field_count = `#[derive(From)]` used on a struc
builtin_macros_derive_from_usage_note = `#[derive(From)]` can only be used on structs with exactly one field
builtin_macros_incomplete_include = include macro expected single expression in source
builtin_macros_multiple_default_attrs = multiple `#[default]` attributes
.note = only one `#[default]` attribute is needed
.label = `#[default]` used here
@ -294,3 +303,5 @@ builtin_macros_unexpected_lit = expected path to a trait, found literal
.label = not a trait
.str_lit = try using `#[derive({$sym})]`
.other = for example, write `#[derive(Debug)]` for `Debug`
builtin_macros_unnameable_test_items = cannot test inner items

View file

@ -1,4 +1,3 @@
use lint::BuiltinLintDiag;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{AsmMacro, token};
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
@ -352,7 +351,7 @@ fn expand_preparsed_asm(
lint::builtin::BAD_ASM_STYLE,
find_span(".intel_syntax"),
ecx.current_expansion.lint_node_id,
BuiltinLintDiag::AvoidUsingIntelSyntax,
errors::AvoidIntelSyntax,
);
}
if template_str.contains(".att_syntax") {
@ -360,7 +359,7 @@ fn expand_preparsed_asm(
lint::builtin::BAD_ASM_STYLE,
find_span(".att_syntax"),
ecx.current_expansion.lint_node_id,
BuiltinLintDiag::AvoidUsingAttSyntax,
errors::AvoidAttSyntax,
);
}
}

View file

@ -1,8 +1,8 @@
mod context;
use rustc_ast::token::{self, Delimiter};
use rustc_ast::token::Delimiter;
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment};
use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment, UnOp, token};
use rustc_ast_pretty::pprust;
use rustc_errors::PResult;
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
@ -29,7 +29,7 @@ pub(crate) fn expand_assert<'cx>(
// `core::panic` and `std::panic` are different macros, so we use call-site
// context to pick up whichever is currently in scope.
let call_site_span = cx.with_call_site_ctxt(cond_expr.span);
let call_site_span = cx.with_call_site_ctxt(span);
let panic_path = || {
if use_panic_2021(span) {
@ -63,7 +63,7 @@ pub(crate) fn expand_assert<'cx>(
}),
})),
);
assert_cond_check(cx, call_site_span, cond_expr, then)
expr_if_not(cx, call_site_span, cond_expr, then, None)
}
// If `generic_assert` is enabled, generates rich captured outputs
//
@ -88,33 +88,26 @@ pub(crate) fn expand_assert<'cx>(
)),
)],
);
assert_cond_check(cx, call_site_span, cond_expr, then)
expr_if_not(cx, call_site_span, cond_expr, then, None)
};
ExpandResult::Ready(MacEager::expr(expr))
}
/// `assert!($cond_expr, $custom_message)`
struct Assert {
cond_expr: Box<Expr>,
custom_message: Option<TokenStream>,
}
/// `match <cond> { true => {} _ => <then> }`
fn assert_cond_check(cx: &ExtCtxt<'_>, span: Span, cond: Box<Expr>, then: Box<Expr>) -> Box<Expr> {
// Instead of expanding to `if !<cond> { <then> }`, we expand to
// `match <cond> { true => {} _ => <then> }`.
// This allows us to always complain about mismatched types instead of "cannot apply unary
// operator `!` to type `X`" when passing an invalid `<cond>`, while also allowing `<cond>` to
// be `&true`.
let els = cx.expr_block(cx.block(span, thin_vec![]));
let mut arms = thin_vec![];
arms.push(cx.arm(span, cx.pat_lit(span, cx.expr_bool(span, true)), els));
arms.push(cx.arm(span, cx.pat_wild(span), then));
// We wrap the `match` in a statement to limit the length of any borrows introduced in the
// condition.
cx.expr_block(cx.block(span, [cx.stmt_expr(cx.expr_match(span, cond, arms))].into()))
// if !{ ... } { ... } else { ... }
fn expr_if_not(
cx: &ExtCtxt<'_>,
span: Span,
cond: Box<Expr>,
then: Box<Expr>,
els: Option<Box<Expr>>,
) -> Box<Expr> {
cx.expr_if(span, cx.expr(span, ExprKind::Unary(UnOp::Not, cond)), then, els)
}
fn parse_assert<'a>(cx: &ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PResult<'a, Assert> {

View file

@ -209,7 +209,8 @@ mod llvm_enzyme {
mut item: Annotatable,
mode: DiffMode,
) -> Vec<Annotatable> {
if cfg!(not(llvm_enzyme)) {
// FIXME(bjorn3) maybe have the backend directly tell if autodiff is supported?
if cfg!(not(feature = "llvm_enzyme")) {
ecx.sess.dcx().emit_err(errors::AutoDiffSupportNotBuild { span: meta_item.span });
return vec![item];
}

View file

@ -51,43 +51,4 @@ pub(crate) fn expand_deriving_const_param_ty(
};
trait_def.expand(cx, mitem, item, push);
let trait_def = TraitDef {
span,
path: path_std!(marker::UnsizedConstParamTy),
skip_path_as_bound: false,
needs_copy_as_bound_if_packed: false,
additional_bounds: vec![ty::Ty::Path(path_std!(cmp::Eq))],
supports_unions: false,
methods: Vec::new(),
associated_types: Vec::new(),
is_const,
is_staged_api_crate: cx.ecfg.features.staged_api(),
};
trait_def.expand(cx, mitem, item, push);
}
pub(crate) fn expand_deriving_unsized_const_param_ty(
cx: &ExtCtxt<'_>,
span: Span,
mitem: &MetaItem,
item: &Annotatable,
push: &mut dyn FnMut(Annotatable),
is_const: bool,
) {
let trait_def = TraitDef {
span,
path: path_std!(marker::UnsizedConstParamTy),
skip_path_as_bound: false,
needs_copy_as_bound_if_packed: false,
additional_bounds: vec![ty::Ty::Path(path_std!(cmp::Eq))],
supports_unions: false,
methods: Vec::new(),
associated_types: Vec::new(),
is_const,
is_staged_api_crate: cx.ecfg.features.staged_api(),
};
trait_def.expand(cx, mitem, item, push);
}

View file

@ -3,9 +3,29 @@ use rustc_errors::{
Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan, SingleLabelManySpans,
Subdiagnostic,
};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_span::{Ident, Span, Symbol};
#[derive(LintDiagnostic)]
#[diag(builtin_macros_avoid_intel_syntax)]
pub(crate) struct AvoidIntelSyntax;
#[derive(LintDiagnostic)]
#[diag(builtin_macros_avoid_att_syntax)]
pub(crate) struct AvoidAttSyntax;
#[derive(LintDiagnostic)]
#[diag(builtin_macros_incomplete_include)]
pub(crate) struct IncompleteInclude;
#[derive(LintDiagnostic)]
#[diag(builtin_macros_unnameable_test_items)]
pub(crate) struct UnnameableTestItems;
#[derive(LintDiagnostic)]
#[diag(builtin_macros_duplicate_macro_attribute)]
pub(crate) struct DuplicateMacroAttribute;
#[derive(Diagnostic)]
#[diag(builtin_macros_requires_cfg_pattern)]
pub(crate) struct RequiresCfgPattern {

View file

@ -565,9 +565,11 @@ fn make_format_args(
&used,
&args,
&pieces,
&invalid_refs,
detect_foreign_fmt,
str_style,
fmt_str,
uncooked_fmt_str.1.as_str(),
fmt_span,
);
}
@ -645,9 +647,11 @@ fn report_missing_placeholders(
used: &[bool],
args: &FormatArguments,
pieces: &[parse::Piece<'_>],
invalid_refs: &[(usize, Option<Span>, PositionUsedAs, FormatArgPositionKind)],
detect_foreign_fmt: bool,
str_style: Option<usize>,
fmt_str: &str,
uncooked_fmt_str: &str,
fmt_span: Span,
) {
let mut diag = if let &[(span, named)] = &unused[..] {
@ -762,6 +766,35 @@ fn report_missing_placeholders(
diag.span_label(fmt_span, "formatting specifier missing");
}
if !found_foreign && invalid_refs.is_empty() {
// Show example if user didn't use any format specifiers
let show_example = used.iter().all(|used| !used);
if !show_example {
if unused.len() > 1 {
diag.note(format!("consider adding {} format specifiers", unused.len()));
}
} else {
let msg = if unused.len() == 1 {
"a format specifier".to_string()
} else {
format!("{} format specifiers", unused.len())
};
let sugg = match str_style {
None => format!("\"{}{}\"", uncooked_fmt_str, "{}".repeat(unused.len())),
Some(n_hashes) => format!(
"r{hashes}\"{uncooked_fmt_str}{fmt_specifiers}\"{hashes}",
hashes = "#".repeat(n_hashes),
fmt_specifiers = "{}".repeat(unused.len())
),
};
let msg = format!("format specifiers use curly braces, consider adding {msg}");
diag.span_suggestion_verbose(fmt_span, msg, sugg, Applicability::MaybeIncorrect);
}
}
diag.emit();
}

View file

@ -129,7 +129,6 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
Clone: clone::expand_deriving_clone,
Copy: bounds::expand_deriving_copy,
ConstParamTy: bounds::expand_deriving_const_param_ty,
UnsizedConstParamTy: bounds::expand_deriving_unsized_const_param_ty,
Debug: debug::expand_deriving_debug,
Default: default::expand_deriving_default,
Eq: eq::expand_deriving_eq,

View file

@ -1,3 +1,5 @@
//! The implementation of built-in macros which relate to the file system.
use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::sync::Arc;
@ -10,10 +12,11 @@ use rustc_expand::base::{
DummyResult, ExpandResult, ExtCtxt, MacEager, MacResult, MacroExpanderResult, resolve_path,
};
use rustc_expand::module::DirOwnership;
use rustc_lint_defs::BuiltinLintDiag;
use rustc_parse::parser::{ForceCollect, Parser};
use rustc_parse::lexer::StripTokens;
use rustc_parse::parser::ForceCollect;
use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal, utf8_error};
use rustc_session::lint::builtin::INCOMPLETE_INCLUDE;
use rustc_session::parse::ParseSess;
use rustc_span::source_map::SourceMap;
use rustc_span::{ByteSymbol, Pos, Span, Symbol};
use smallvec::SmallVec;
@ -23,11 +26,7 @@ use crate::util::{
check_zero_tts, get_single_str_from_tts, get_single_str_spanned_from_tts, parse_expr,
};
// These macros all relate to the file system; they either return
// the column/row/filename of the expression, or they include
// a given file into the current one.
/// line!(): expands to the current line number
/// Expand `line!()` to the current line number.
pub(crate) fn expand_line(
cx: &mut ExtCtxt<'_>,
sp: Span,
@ -42,7 +41,7 @@ pub(crate) fn expand_line(
ExpandResult::Ready(MacEager::expr(cx.expr_u32(topmost, loc.line as u32)))
}
/* column!(): expands to the current column number */
/// Expand `column!()` to the current column number.
pub(crate) fn expand_column(
cx: &mut ExtCtxt<'_>,
sp: Span,
@ -57,9 +56,7 @@ pub(crate) fn expand_column(
ExpandResult::Ready(MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32 + 1)))
}
/// file!(): expands to the current filename */
/// The source_file (`loc.file`) contains a bunch more information we could spit
/// out if we wanted.
/// Expand `file!()` to the current filename.
pub(crate) fn expand_file(
cx: &mut ExtCtxt<'_>,
sp: Span,
@ -81,6 +78,7 @@ pub(crate) fn expand_file(
)))
}
/// Expand `stringify!($input)`.
pub(crate) fn expand_stringify(
cx: &mut ExtCtxt<'_>,
sp: Span,
@ -91,6 +89,7 @@ pub(crate) fn expand_stringify(
ExpandResult::Ready(MacEager::expr(cx.expr_str(sp, Symbol::intern(&s))))
}
/// Expand `module_path!()` to (a textual representation of) the current module path.
pub(crate) fn expand_mod(
cx: &mut ExtCtxt<'_>,
sp: Span,
@ -104,9 +103,9 @@ pub(crate) fn expand_mod(
ExpandResult::Ready(MacEager::expr(cx.expr_str(sp, Symbol::intern(&string))))
}
/// include! : parse the given file as an expr
/// This is generally a bad idea because it's going to behave
/// unhygienically.
/// Expand `include!($input)`.
///
/// This works in item and expression position. Notably, it doesn't work in pattern position.
pub(crate) fn expand_include<'cx>(
cx: &'cx mut ExtCtxt<'_>,
sp: Span,
@ -116,64 +115,76 @@ pub(crate) fn expand_include<'cx>(
let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "include!") else {
return ExpandResult::Retry(());
};
let file = match mac {
Ok(file) => file,
let path = match mac {
Ok(path) => path,
Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
};
// The file will be added to the code map by the parser
let file = match resolve_path(&cx.sess, file.as_str(), sp) {
Ok(f) => f,
let path = match resolve_path(&cx.sess, path.as_str(), sp) {
Ok(path) => path,
Err(err) => {
let guar = err.emit();
return ExpandResult::Ready(DummyResult::any(sp, guar));
}
};
let p = unwrap_or_emit_fatal(new_parser_from_file(cx.psess(), &file, Some(sp)));
// If in the included file we have e.g., `mod bar;`,
// then the path of `bar.rs` should be relative to the directory of `file`.
// then the path of `bar.rs` should be relative to the directory of `path`.
// See https://github.com/rust-lang/rust/pull/69838/files#r395217057 for a discussion.
// `MacroExpander::fully_expand_fragment` later restores, so "stack discipline" is maintained.
let dir_path = file.parent().unwrap_or(&file).to_owned();
let dir_path = path.parent().unwrap_or(&path).to_owned();
cx.current_expansion.module = Rc::new(cx.current_expansion.module.with_dir_path(dir_path));
cx.current_expansion.dir_ownership = DirOwnership::Owned { relative: None };
struct ExpandInclude<'a> {
p: Parser<'a>,
psess: &'a ParseSess,
path: PathBuf,
node_id: ast::NodeId,
span: Span,
}
impl<'a> MacResult for ExpandInclude<'a> {
fn make_expr(mut self: Box<ExpandInclude<'a>>) -> Option<Box<ast::Expr>> {
let expr = parse_expr(&mut self.p).ok()?;
if self.p.token != token::Eof {
self.p.psess.buffer_lint(
fn make_expr(self: Box<ExpandInclude<'a>>) -> Option<Box<ast::Expr>> {
let mut p = unwrap_or_emit_fatal(new_parser_from_file(
self.psess,
&self.path,
// Don't strip frontmatter for backward compatibility, `---` may be the start of a
// manifold negation. FIXME: Ideally, we wouldn't strip shebangs here either.
StripTokens::Shebang,
Some(self.span),
));
let expr = parse_expr(&mut p).ok()?;
if p.token != token::Eof {
p.psess.buffer_lint(
INCOMPLETE_INCLUDE,
self.p.token.span,
p.token.span,
self.node_id,
BuiltinLintDiag::IncompleteInclude,
errors::IncompleteInclude,
);
}
Some(expr)
}
fn make_items(mut self: Box<ExpandInclude<'a>>) -> Option<SmallVec<[Box<ast::Item>; 1]>> {
fn make_items(self: Box<ExpandInclude<'a>>) -> Option<SmallVec<[Box<ast::Item>; 1]>> {
let mut p = unwrap_or_emit_fatal(new_parser_from_file(
self.psess,
&self.path,
StripTokens::ShebangAndFrontmatter,
Some(self.span),
));
let mut ret = SmallVec::new();
loop {
match self.p.parse_item(ForceCollect::No) {
match p.parse_item(ForceCollect::No) {
Err(err) => {
err.emit();
break;
}
Ok(Some(item)) => ret.push(item),
Ok(None) => {
if self.p.token != token::Eof {
self.p
.dcx()
.create_err(errors::ExpectedItem {
span: self.p.token.span,
token: &pprust::token_to_string(&self.p.token),
})
.emit();
if p.token != token::Eof {
p.dcx().emit_err(errors::ExpectedItem {
span: p.token.span,
token: &pprust::token_to_string(&p.token),
});
}
break;
@ -184,10 +195,17 @@ pub(crate) fn expand_include<'cx>(
}
}
ExpandResult::Ready(Box::new(ExpandInclude { p, node_id: cx.current_expansion.lint_node_id }))
ExpandResult::Ready(Box::new(ExpandInclude {
psess: cx.psess(),
path,
node_id: cx.current_expansion.lint_node_id,
span: sp,
}))
}
/// `include_str!`: read the given file, insert it as a literal string expr
/// Expand `include_str!($input)` to the content of the UTF-8-encoded file given by path `$input` as a string literal.
///
/// This works in expression, pattern and statement position.
pub(crate) fn expand_include_str(
cx: &mut ExtCtxt<'_>,
sp: Span,
@ -206,6 +224,7 @@ pub(crate) fn expand_include_str(
Ok((bytes, bsp)) => match std::str::from_utf8(&bytes) {
Ok(src) => {
let interned_src = Symbol::intern(src);
// MacEager converts the expr into a pat if need be.
MacEager::expr(cx.expr_str(cx.with_def_site_ctxt(bsp), interned_src))
}
Err(utf8err) => {
@ -218,6 +237,9 @@ pub(crate) fn expand_include_str(
})
}
/// Expand `include_bytes!($input)` to the content of the file given by path `$input`.
///
/// This works in expression, pattern and statement position.
pub(crate) fn expand_include_bytes(
cx: &mut ExtCtxt<'_>,
sp: Span,
@ -237,6 +259,7 @@ pub(crate) fn expand_include_bytes(
// Don't care about getting the span for the raw bytes,
// because the console can't really show them anyway.
let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(ByteSymbol::intern(&bytes)));
// MacEager converts the expr into a pat if need be.
MacEager::expr(expr)
}
Err(dummy) => dummy,

View file

@ -11,7 +11,6 @@ use rustc_errors::DiagCtxtHandle;
use rustc_expand::base::{ExtCtxt, ResolverExpand};
use rustc_expand::expand::{AstFragment, ExpansionConfig};
use rustc_feature::Features;
use rustc_lint_defs::BuiltinLintDiag;
use rustc_session::Session;
use rustc_session::lint::builtin::UNNAMEABLE_TEST_ITEMS;
use rustc_span::hygiene::{AstPass, SyntaxContext, Transparency};
@ -165,7 +164,7 @@ impl<'a> Visitor<'a> for InnerItemLinter<'_> {
UNNAMEABLE_TEST_ITEMS,
attr.span,
i.id,
BuiltinLintDiag::UnnameableTestItems,
errors::UnnameableTestItems,
);
}
}

View file

@ -5,7 +5,6 @@ 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};
use rustc_session::errors::report_lit_error;
@ -49,7 +48,7 @@ pub(crate) fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable,
DUPLICATE_MACRO_ATTRIBUTES,
attr.span,
ecx.current_expansion.lint_node_id,
BuiltinLintDiag::DuplicateMacroAttribute,
errors::DuplicateMacroAttribute,
);
}
}

View file

@ -715,7 +715,7 @@ pub(crate) fn codegen_drop<'tcx>(
fx.bcx.ins().jump(ret_block, &[]);
} else {
match ty.kind() {
ty::Dynamic(_, _, ty::Dyn) => {
ty::Dynamic(_, _) => {
// IN THIS ARM, WE HAVE:
// ty = *mut (dyn Trait)
// which is: exists<T> ( *mut T, Vtable<T: Trait> )

View file

@ -834,12 +834,6 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt:
fx.bcx.ins().nop();
}
}
Rvalue::Len(place) => {
let place = codegen_place(fx, place);
let usize_layout = fx.layout_of(fx.tcx.types.usize);
let len = codegen_array_len(fx, place);
lval.write_cvalue(fx, CValue::by_val(len, usize_layout));
}
Rvalue::ShallowInitBox(ref operand, content_ty) => {
let content_ty = fx.monomorphize(content_ty);
let box_layout = fx.layout_of(Ty::new_box(fx.tcx, content_ty));

View file

@ -30,9 +30,7 @@ pub(crate) fn unsized_info<'tcx>(
fx.pointer_type,
len.try_to_target_usize(fx.tcx).expect("expected monomorphic const in codegen") as i64,
),
(&ty::Dynamic(data_a, _, src_dyn_kind), &ty::Dynamic(data_b, _, target_dyn_kind))
if src_dyn_kind == target_dyn_kind =>
{
(&ty::Dynamic(data_a, _), &ty::Dynamic(data_b, _)) => {
let old_info =
old_info.expect("unsized_info: missing old info for trait upcasting coercion");
let b_principal_def_id = data_b.principal_def_id();

View file

@ -909,8 +909,7 @@ pub(crate) fn assert_assignable<'tcx>(
);
// fn(&T) -> for<'l> fn(&'l T) is allowed
}
(&ty::Dynamic(from_traits, _, _from_kind), &ty::Dynamic(to_traits, _, _to_kind)) => {
// FIXME(dyn-star): Do the right thing with DynKinds
(&ty::Dynamic(from_traits, _), &ty::Dynamic(to_traits, _)) => {
for (from, to) in from_traits.iter().zip(to_traits) {
let from = fx.tcx.normalize_erasing_late_bound_regions(fx.typing_env(), from);
let to = fx.tcx.normalize_erasing_late_bound_regions(fx.typing_env(), to);

View file

@ -81,6 +81,8 @@ impl<'gcc, 'tcx> StaticCodegenMethods for CodegenCx<'gcc, 'tcx> {
if global.to_rvalue().get_type() != val_llty {
global.to_rvalue().set_type(val_llty);
}
// NOTE: Alignment from attributes has already been applied to the allocation.
set_global_alignment(self, global, alloc.align);
global.global_set_initializer_rvalue(value);

View file

@ -730,7 +730,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
if self.is_sized_indirect() {
OperandValue::Ref(PlaceValue::new_sized(val, self.layout.align.abi)).store(bx, dst)
} else if self.is_unsized_indirect() {
bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
bug!("unsized `ArgAbi` cannot be stored");
} else if let PassMode::Cast { ref cast, .. } = self.mode {
// FIXME(eddyb): Figure out when the simpler Store is safe, clang
// uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
@ -797,12 +797,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
OperandValue::Pair(next(), next()).store(bx, dst);
}
PassMode::Indirect { meta_attrs: Some(_), .. } => {
let place_val = PlaceValue {
llval: next(),
llextra: Some(next()),
align: self.layout.align.abi,
};
OperandValue::Ref(place_val).store(bx, dst);
bug!("unsized `ArgAbi` cannot be stored");
}
PassMode::Direct(_)
| PassMode::Indirect { meta_attrs: None, .. }

View file

@ -240,7 +240,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
// Make sure lifetimes are erased, to avoid generating distinct LLVM
// types for Rust types that only differ in the choice of lifetimes.
let normal_ty = cx.tcx.erase_regions(self.ty);
let normal_ty = cx.tcx.erase_and_anonymize_regions(self.ty);
let mut defer = None;
let ty = if self.ty != normal_ty {

View file

@ -46,5 +46,6 @@ tracing = "0.1"
[features]
# tidy-alphabetical-start
check_only = ["rustc_llvm/check_only"]
llvm_enzyme = []
# tidy-alphabetical-end

View file

@ -215,9 +215,9 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
let align = attrs.pointee_align.unwrap_or(self.layout.align.abi);
OperandValue::Ref(PlaceValue::new_sized(val, align)).store(bx, dst);
}
// Unsized indirect qrguments
// Unsized indirect arguments cannot be stored
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
bug!("unsized `ArgAbi` cannot be stored");
}
PassMode::Cast { cast, pad_i32: _ } => {
// The ABI mandates that the value is passed as a different struct representation.
@ -272,12 +272,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
OperandValue::Pair(next(), next()).store(bx, dst);
}
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
let place_val = PlaceValue {
llval: next(),
llextra: Some(next()),
align: self.layout.align.abi,
};
OperandValue::Ref(place_val).store(bx, dst);
bug!("unsized `ArgAbi` cannot be stored");
}
PassMode::Direct(_)
| PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ }

View file

@ -240,6 +240,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
}
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
constraints.extend_from_slice(&[
"~{fflags}".to_string(),
"~{vtype}".to_string(),
"~{vl}".to_string(),
"~{vxsat}".to_string(),

View file

@ -0,0 +1,37 @@
#[cfg(test)]
mod tests;
/// Joins command-line arguments into a single space-separated string, quoting
/// and escaping individual arguments as necessary.
///
/// The result is intended to be informational, for embedding in debug metadata,
/// and might not be properly quoted/escaped for actual command-line use.
pub(crate) fn quote_command_line_args(args: &[String]) -> String {
// Start with a decent-sized buffer, since rustc invocations tend to be long.
let mut buf = String::with_capacity(128);
for arg in args {
if !buf.is_empty() {
buf.push(' ');
}
print_arg_quoted(&mut buf, arg);
}
buf
}
/// Equivalent to LLVM's `sys::printArg` with quoting always enabled
/// (see llvm/lib/Support/Program.cpp).
fn print_arg_quoted(buf: &mut String, arg: &str) {
buf.reserve(arg.len() + 2);
buf.push('"');
for ch in arg.chars() {
if matches!(ch, '"' | '\\' | '$') {
buf.push('\\');
}
buf.push(ch);
}
buf.push('"');
}

View file

@ -0,0 +1,25 @@
#[test]
fn quote_command_line_args() {
use super::quote_command_line_args;
struct Case<'a> {
args: &'a [&'a str],
expected: &'a str,
}
let cases = &[
Case { args: &[], expected: "" },
Case { args: &["--hello", "world"], expected: r#""--hello" "world""# },
Case { args: &["--hello world"], expected: r#""--hello world""# },
Case {
args: &["plain", "$dollar", "spa ce", r"back\slash", r#""quote""#, "plain"],
expected: r#""plain" "\$dollar" "spa ce" "back\\slash" "\"quote\"" "plain""#,
},
];
for &Case { args, expected } in cases {
let args = args.iter().copied().map(str::to_owned).collect::<Vec<_>>();
let actual = quote_command_line_args(&args);
assert_eq!(actual, expected, "args {args:?}");
}
}

View file

@ -617,7 +617,7 @@ pub(crate) fn run_pass_manager(
crate::builder::gpu_offload::handle_gpu_code(cgcx, &cx);
}
if cfg!(llvm_enzyme) && enable_ad && !thin {
if cfg!(feature = "llvm_enzyme") && enable_ad && !thin {
let opt_stage = llvm::OptStage::FatLTO;
let stage = write::AutodiffStage::PostAD;
if !config.autodiff.contains(&config::AutoDiff::NoPostopt) {

View file

@ -1,4 +1,5 @@
pub(crate) mod archive;
mod command_line_args;
pub(crate) mod lto;
pub(crate) mod owned_target_machine;
mod profiling;

View file

@ -1,4 +1,3 @@
use std::assert_matches::assert_matches;
use std::ffi::CStr;
use std::marker::PhantomData;
use std::ptr::NonNull;
@ -39,13 +38,10 @@ impl OwnedTargetMachine {
output_obj_file: &CStr,
debug_info_compression: &CStr,
use_emulated_tls: bool,
args_cstr_buff: &[u8],
argv0: &str,
command_line_args: &str,
use_wasm_eh: bool,
) -> Result<Self, LlvmError<'static>> {
// The argument list is passed as the concatenation of one or more C strings.
// This implies that there must be a last byte, and it must be 0.
assert_matches!(args_cstr_buff, [.., b'\0'], "the last byte must be a NUL terminator");
// SAFETY: llvm::LLVMRustCreateTargetMachine copies pointed to data
let tm_ptr = unsafe {
llvm::LLVMRustCreateTargetMachine(
@ -70,8 +66,10 @@ impl OwnedTargetMachine {
output_obj_file.as_ptr(),
debug_info_compression.as_ptr(),
use_emulated_tls,
args_cstr_buff.as_ptr(),
args_cstr_buff.len(),
argv0.as_ptr(),
argv0.len(),
command_line_args.as_ptr(),
command_line_args.len(),
use_wasm_eh,
)
};

View file

@ -31,6 +31,7 @@ use rustc_span::{BytePos, InnerSpan, Pos, SpanData, SyntaxContext, sym};
use rustc_target::spec::{CodeModel, FloatAbi, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel};
use tracing::{debug, trace};
use crate::back::command_line_args::quote_command_line_args;
use crate::back::lto::ThinBuffer;
use crate::back::owned_target_machine::OwnedTargetMachine;
use crate::back::profiling::{
@ -249,23 +250,15 @@ pub(crate) fn target_machine_factory(
let use_emulated_tls = matches!(sess.tls_model(), TlsModel::Emulated);
// copy the exe path, followed by path all into one buffer
// null terminating them so we can use them as null terminated strings
let args_cstr_buff = {
let mut args_cstr_buff: Vec<u8> = Vec::new();
let exe_path = std::env::current_exe().unwrap_or_default();
let exe_path_str = exe_path.into_os_string().into_string().unwrap_or_default();
args_cstr_buff.extend_from_slice(exe_path_str.as_bytes());
args_cstr_buff.push(0);
for arg in sess.expanded_args.iter() {
args_cstr_buff.extend_from_slice(arg.as_bytes());
args_cstr_buff.push(0);
}
args_cstr_buff
};
// Command-line information to be included in the target machine.
// This seems to only be used for embedding in PDB debuginfo files.
// FIXME(Zalathar): Maybe skip this for non-PDB targets?
let argv0 = std::env::current_exe()
.unwrap_or_default()
.into_os_string()
.into_string()
.unwrap_or_default();
let command_line_args = quote_command_line_args(&sess.expanded_args);
let debuginfo_compression = sess.opts.debuginfo_compression.to_string();
match sess.opts.debuginfo_compression {
@ -323,7 +316,8 @@ pub(crate) fn target_machine_factory(
&output_obj_file,
&debuginfo_compression,
use_emulated_tls,
&args_cstr_buff,
&argv0,
&command_line_args,
use_wasm_eh,
)
})
@ -574,7 +568,8 @@ pub(crate) unsafe fn llvm_optimize(
// FIXME(ZuseZ4): In a future update we could figure out how to only optimize individual functions getting
// differentiated.
let consider_ad = cfg!(llvm_enzyme) && config.autodiff.contains(&config::AutoDiff::Enable);
let consider_ad =
cfg!(feature = "llvm_enzyme") && config.autodiff.contains(&config::AutoDiff::Enable);
let run_enzyme = autodiff_stage == AutodiffStage::DuringAD;
let print_before_enzyme = config.autodiff.contains(&config::AutoDiff::PrintModBefore);
let print_after_enzyme = config.autodiff.contains(&config::AutoDiff::PrintModAfter);
@ -740,7 +735,8 @@ pub(crate) fn optimize(
// If we know that we will later run AD, then we disable vectorization and loop unrolling.
// Otherwise we pretend AD is already done and run the normal opt pipeline (=PostAD).
let consider_ad = cfg!(llvm_enzyme) && config.autodiff.contains(&config::AutoDiff::Enable);
let consider_ad =
cfg!(feature = "llvm_enzyme") && config.autodiff.contains(&config::AutoDiff::Enable);
let autodiff_stage = if consider_ad { AutodiffStage::PreAD } else { AutodiffStage::PostAD };
// The embedded bitcode is used to run LTO/ThinLTO.
// The bitcode obtained during the `codegen` phase is no longer suitable for performing LTO.

View file

@ -109,18 +109,36 @@ pub(crate) fn compile_codegen_unit(
attributes::apply_to_llfn(entry, llvm::AttributePlace::Function, &attrs);
}
// Define Objective-C module info and module flags. Note, the module info will
// also be added to the `llvm.compiler.used` variable, created later.
//
// These are only necessary when we need the linker to do its Objective-C-specific
// magic. We could theoretically do it unconditionally, but at a slight cost to linker
// performance in the common case where it's unnecessary.
if !cx.objc_classrefs.borrow().is_empty() || !cx.objc_selrefs.borrow().is_empty() {
if cx.objc_abi_version() == 1 {
cx.define_objc_module_info();
}
cx.add_objc_module_flags();
}
// Finalize code coverage by injecting the coverage map. Note, the coverage map will
// also be added to the `llvm.compiler.used` variable, created next.
if cx.sess().instrument_coverage() {
cx.coverageinfo_finalize();
}
// Create the llvm.used and llvm.compiler.used variables.
// Create the llvm.used variable.
if !cx.used_statics.is_empty() {
cx.create_used_variable_impl(c"llvm.used", &cx.used_statics);
}
if !cx.compiler_used_statics.is_empty() {
cx.create_used_variable_impl(c"llvm.compiler.used", &cx.compiler_used_statics);
// Create the llvm.compiler.used variable.
{
let compiler_used_statics = cx.compiler_used_statics.borrow();
if !compiler_used_statics.is_empty() {
cx.create_used_variable_impl(c"llvm.compiler.used", &compiler_used_statics);
}
}
// Run replace-all-uses-with for statics that need it. This must

View file

@ -1091,16 +1091,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
ty: Ty<'tcx>,
lhs: Self::Value,
rhs: Self::Value,
) -> Option<Self::Value> {
// FIXME: See comment on the definition of `three_way_compare`.
if crate::llvm_util::get_version() < (20, 0, 0) {
return None;
}
) -> Self::Value {
let size = ty.primitive_size(self.tcx);
let name = if ty.is_signed() { "llvm.scmp" } else { "llvm.ucmp" };
Some(self.call_intrinsic(name, &[self.type_i8(), self.type_ix(size.bits())], &[lhs, rhs]))
self.call_intrinsic(name, &[self.type_i8(), self.type_ix(size.bits())], &[lhs, rhs])
}
/* Miscellaneous instructions */

View file

@ -3,8 +3,9 @@ use std::ptr;
use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode};
use rustc_codegen_ssa::common::TypeKind;
use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, BuilderMethods};
use rustc_middle::ty::{PseudoCanonicalInput, Ty, TyCtxt, TypingEnv};
use rustc_middle::ty::{Instance, PseudoCanonicalInput, TyCtxt, TypingEnv};
use rustc_middle::{bug, ty};
use rustc_target::callconv::PassMode;
use tracing::debug;
use crate::builder::{Builder, PlaceRef, UNNAMED};
@ -16,9 +17,12 @@ use crate::value::Value;
pub(crate) fn adjust_activity_to_abi<'tcx>(
tcx: TyCtxt<'tcx>,
fn_ty: Ty<'tcx>,
instance: Instance<'tcx>,
typing_env: TypingEnv<'tcx>,
da: &mut Vec<DiffActivity>,
) {
let fn_ty = instance.ty(tcx, typing_env);
if !matches!(fn_ty.kind(), ty::FnDef(..)) {
bug!("expected fn def for autodiff, got {:?}", fn_ty);
}
@ -27,8 +31,16 @@ pub(crate) fn adjust_activity_to_abi<'tcx>(
// All we do is decide how to handle the arguments.
let sig = fn_ty.fn_sig(tcx).skip_binder();
// FIXME(Sa4dUs): pass proper varargs once we have support for differentiating variadic functions
let Ok(fn_abi) =
tcx.fn_abi_of_instance(typing_env.as_query_input((instance, ty::List::empty())))
else {
bug!("failed to get fn_abi of instance with empty varargs");
};
let mut new_activities = vec![];
let mut new_positions = vec![];
let mut del_activities = 0;
for (i, ty) in sig.inputs().iter().enumerate() {
if let Some(inner_ty) = ty.builtin_deref(true) {
if inner_ty.is_slice() {
@ -80,6 +92,34 @@ pub(crate) fn adjust_activity_to_abi<'tcx>(
continue;
}
}
let pci = PseudoCanonicalInput { typing_env: TypingEnv::fully_monomorphized(), value: *ty };
let layout = match tcx.layout_of(pci) {
Ok(layout) => layout.layout,
Err(_) => {
bug!("failed to compute layout for type {:?}", ty);
}
};
let pass_mode = &fn_abi.args[i].mode;
// For ZST, just ignore and don't add its activity, as this arg won't be present
// in the LLVM passed to Enzyme.
// Some targets pass ZST indirectly in the C ABI, in that case, handle it as a normal arg
// FIXME(Sa4dUs): Enforce ZST corresponding diff activity be `Const`
if *pass_mode == PassMode::Ignore {
del_activities += 1;
da.remove(i);
}
// If the argument is lowered as a `ScalarPair`, we need to duplicate its activity.
// Otherwise, the number of activities won't match the number of LLVM arguments and
// this will lead to errors when verifying the Enzyme call.
if let rustc_abi::BackendRepr::ScalarPair(_, _) = layout.backend_repr() {
new_activities.push(da[i].clone());
new_positions.push(i + 1 - del_activities);
}
}
// now add the extra activities coming from slices
// Reverse order to not invalidate the indices

View file

@ -108,6 +108,10 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
bytes_in_context(self.llcx(), bytes)
}
pub(crate) fn null_terminate_const_bytes(&self, bytes: &[u8]) -> &'ll Value {
null_terminate_bytes_in_context(self.llcx(), bytes)
}
pub(crate) fn const_get_elt(&self, v: &'ll Value, idx: u64) -> &'ll Value {
unsafe {
let idx = c_uint::try_from(idx).expect("LLVMGetAggregateElement index overflow");
@ -381,6 +385,16 @@ pub(crate) fn bytes_in_context<'ll>(llcx: &'ll llvm::Context, bytes: &[u8]) -> &
}
}
pub(crate) fn null_terminate_bytes_in_context<'ll>(
llcx: &'ll llvm::Context,
bytes: &[u8],
) -> &'ll Value {
unsafe {
let ptr = bytes.as_ptr() as *const c_char;
llvm::LLVMConstStringInContext2(llcx, ptr, bytes.len(), FALSE)
}
}
pub(crate) fn named_struct<'ll>(ty: &'ll Type, elts: &[&'ll Value]) -> &'ll Value {
let len = c_uint::try_from(elts.len()).expect("LLVMConstStructInContext elements len overflow");
unsafe { llvm::LLVMConstNamedStruct(ty, elts.as_ptr(), len) }

View file

@ -16,6 +16,7 @@ use rustc_middle::mir::mono::MonoItem;
use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
use rustc_middle::ty::{self, Instance};
use rustc_middle::{bug, span_bug};
use rustc_span::Symbol;
use tracing::{debug, instrument, trace};
use crate::common::CodegenCx;
@ -331,6 +332,10 @@ impl<'ll> CodegenCx<'ll, '_> {
}
g
} else if let Some(classname) = fn_attrs.objc_class {
self.get_objc_classref(classname)
} else if let Some(methname) = fn_attrs.objc_selector {
self.get_objc_selref(methname)
} else {
check_and_apply_linkage(self, fn_attrs, llty, sym, def_id)
};
@ -452,6 +457,8 @@ impl<'ll> CodegenCx<'ll, '_> {
self.statics_to_rauw.borrow_mut().push((g, new_g));
new_g
};
// NOTE: Alignment from attributes has already been applied to the allocation.
set_global_alignment(self, g, alloc.align);
llvm::set_initializer(g, v);
@ -541,8 +548,225 @@ impl<'ll> CodegenCx<'ll, '_> {
/// Add a global value to a list to be stored in the `llvm.compiler.used` variable,
/// an array of ptr.
pub(crate) fn add_compiler_used_global(&mut self, global: &'ll Value) {
self.compiler_used_statics.push(global);
pub(crate) fn add_compiler_used_global(&self, global: &'ll Value) {
self.compiler_used_statics.borrow_mut().push(global);
}
// We do our best here to match what Clang does when compiling Objective-C natively.
// See Clang's `CGObjCCommonMac::CreateCStringLiteral`:
// https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L4134
fn define_objc_classname(&self, classname: &str) -> &'ll Value {
assert_eq!(self.objc_abi_version(), 1);
let llval = self.null_terminate_const_bytes(classname.as_bytes());
let llty = self.val_ty(llval);
let sym = self.generate_local_symbol_name("OBJC_CLASS_NAME_");
let g = self.define_global(&sym, llty).unwrap_or_else(|| {
bug!("symbol `{}` is already defined", sym);
});
set_global_alignment(self, g, self.tcx.data_layout.i8_align.abi);
llvm::set_initializer(g, llval);
llvm::set_linkage(g, llvm::Linkage::PrivateLinkage);
llvm::set_section(g, c"__TEXT,__cstring,cstring_literals");
llvm::LLVMSetGlobalConstant(g, llvm::TRUE);
llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global);
self.add_compiler_used_global(g);
g
}
// We do our best here to match what Clang does when compiling Objective-C natively.
// See Clang's `ObjCNonFragileABITypesHelper`:
// https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L6052
fn get_objc_class_t(&self) -> &'ll Type {
if let Some(class_t) = self.objc_class_t.get() {
return class_t;
}
assert_eq!(self.objc_abi_version(), 2);
// struct _class_t {
// struct _class_t* isa;
// struct _class_t* const superclass;
// void* cache;
// IMP* vtable;
// struct class_ro_t* ro;
// }
let class_t = self.type_named_struct("struct._class_t");
let els = [self.type_ptr(); 5];
let packed = false;
self.set_struct_body(class_t, &els, packed);
self.objc_class_t.set(Some(class_t));
class_t
}
// We do our best here to match what Clang does when compiling Objective-C natively. We
// deduplicate references within a CGU, but we need a reference definition in each referencing
// CGU. All attempts at using external references to a single reference definition result in
// linker errors.
fn get_objc_classref(&self, classname: Symbol) -> &'ll Value {
let mut classrefs = self.objc_classrefs.borrow_mut();
if let Some(classref) = classrefs.get(&classname).copied() {
return classref;
}
let g = match self.objc_abi_version() {
1 => {
// See Clang's `CGObjCMac::EmitClassRefFromId`:
// https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L5205
let llval = self.define_objc_classname(classname.as_str());
let llty = self.type_ptr();
let sym = self.generate_local_symbol_name("OBJC_CLASS_REFERENCES_");
let g = self.define_global(&sym, llty).unwrap_or_else(|| {
bug!("symbol `{}` is already defined", sym);
});
set_global_alignment(self, g, self.tcx.data_layout.pointer_align().abi);
llvm::set_initializer(g, llval);
llvm::set_linkage(g, llvm::Linkage::PrivateLinkage);
llvm::set_section(g, c"__OBJC,__cls_refs,literal_pointers,no_dead_strip");
self.add_compiler_used_global(g);
g
}
2 => {
// See Clang's `CGObjCNonFragileABIMac::EmitClassRefFromId`:
// https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L7423
let llval = {
let extern_sym = format!("OBJC_CLASS_$_{}", classname.as_str());
let extern_llty = self.get_objc_class_t();
self.declare_global(&extern_sym, extern_llty)
};
let llty = self.type_ptr();
let sym = self.generate_local_symbol_name("OBJC_CLASSLIST_REFERENCES_$_");
let g = self.define_global(&sym, llty).unwrap_or_else(|| {
bug!("symbol `{}` is already defined", sym);
});
set_global_alignment(self, g, self.tcx.data_layout.pointer_align().abi);
llvm::set_initializer(g, llval);
llvm::set_linkage(g, llvm::Linkage::InternalLinkage);
llvm::set_section(g, c"__DATA,__objc_classrefs,regular,no_dead_strip");
self.add_compiler_used_global(g);
g
}
_ => unreachable!(),
};
classrefs.insert(classname, g);
g
}
// We do our best here to match what Clang does when compiling Objective-C natively. We
// deduplicate references within a CGU, but we need a reference definition in each referencing
// CGU. All attempts at using external references to a single reference definition result in
// linker errors.
//
// Newer versions of Apple Clang generate calls to `@"objc_msgSend$methname"` selector stub
// functions. We don't currently do that. The code we generate is closer to what Apple Clang
// generates with the `-fno-objc-msgsend-selector-stubs` option.
fn get_objc_selref(&self, methname: Symbol) -> &'ll Value {
let mut selrefs = self.objc_selrefs.borrow_mut();
if let Some(selref) = selrefs.get(&methname).copied() {
return selref;
}
let abi_version = self.objc_abi_version();
// See Clang's `CGObjCCommonMac::CreateCStringLiteral`:
// https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L4134
let methname_llval = self.null_terminate_const_bytes(methname.as_str().as_bytes());
let methname_llty = self.val_ty(methname_llval);
let methname_sym = self.generate_local_symbol_name("OBJC_METH_VAR_NAME_");
let methname_g = self.define_global(&methname_sym, methname_llty).unwrap_or_else(|| {
bug!("symbol `{}` is already defined", methname_sym);
});
set_global_alignment(self, methname_g, self.tcx.data_layout.i8_align.abi);
llvm::set_initializer(methname_g, methname_llval);
llvm::set_linkage(methname_g, llvm::Linkage::PrivateLinkage);
llvm::set_section(
methname_g,
match abi_version {
1 => c"__TEXT,__cstring,cstring_literals",
2 => c"__TEXT,__objc_methname,cstring_literals",
_ => unreachable!(),
},
);
llvm::LLVMSetGlobalConstant(methname_g, llvm::TRUE);
llvm::LLVMSetUnnamedAddress(methname_g, llvm::UnnamedAddr::Global);
self.add_compiler_used_global(methname_g);
// See Clang's `CGObjCMac::EmitSelectorAddr`:
// https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L5243
// And Clang's `CGObjCNonFragileABIMac::EmitSelectorAddr`:
// https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L7586
let selref_llval = methname_g;
let selref_llty = self.type_ptr();
let selref_sym = self.generate_local_symbol_name("OBJC_SELECTOR_REFERENCES_");
let selref_g = self.define_global(&selref_sym, selref_llty).unwrap_or_else(|| {
bug!("symbol `{}` is already defined", selref_sym);
});
set_global_alignment(self, selref_g, self.tcx.data_layout.pointer_align().abi);
llvm::set_initializer(selref_g, selref_llval);
llvm::set_externally_initialized(selref_g, true);
llvm::set_linkage(
selref_g,
match abi_version {
1 => llvm::Linkage::PrivateLinkage,
2 => llvm::Linkage::InternalLinkage,
_ => unreachable!(),
},
);
llvm::set_section(
selref_g,
match abi_version {
1 => c"__OBJC,__message_refs,literal_pointers,no_dead_strip",
2 => c"__DATA,__objc_selrefs,literal_pointers,no_dead_strip",
_ => unreachable!(),
},
);
self.add_compiler_used_global(selref_g);
selrefs.insert(methname, selref_g);
selref_g
}
// We do our best here to match what Clang does when compiling Objective-C natively.
// See Clang's `ObjCTypesHelper`:
// https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L5936
// And Clang's `CGObjCMac::EmitModuleInfo`:
// https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L5151
pub(crate) fn define_objc_module_info(&mut self) {
assert_eq!(self.objc_abi_version(), 1);
// struct _objc_module {
// long version; // Hardcoded to 7 in Clang.
// long size; // sizeof(struct _objc_module)
// char* name; // Hardcoded to classname "" in Clang.
// struct _objc_symtab* symtab; // Null without class or category definitions.
// }
let llty = self.type_named_struct("struct._objc_module");
let i32_llty = self.type_i32();
let ptr_llty = self.type_ptr();
let packed = false;
self.set_struct_body(llty, &[i32_llty, i32_llty, ptr_llty, ptr_llty], packed);
let version = self.const_uint(i32_llty, 7);
let size = self.const_uint(i32_llty, 16);
let name = self.define_objc_classname("");
let symtab = self.const_null(ptr_llty);
let llval = crate::common::named_struct(llty, &[version, size, name, symtab]);
let sym = "OBJC_MODULES";
let g = self.define_global(&sym, llty).unwrap_or_else(|| {
bug!("symbol `{}` is already defined", sym);
});
set_global_alignment(self, g, self.tcx.data_layout.pointer_align().abi);
llvm::set_initializer(g, llval);
llvm::set_linkage(g, llvm::Linkage::PrivateLinkage);
llvm::set_section(g, c"__OBJC,__module_info,regular,no_dead_strip");
self.add_compiler_used_global(g);
}
}

View file

@ -26,7 +26,7 @@ use rustc_session::config::{
BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, FunctionReturn, PAuthKey, PacRet,
};
use rustc_span::source_map::Spanned;
use rustc_span::{DUMMY_SP, Span};
use rustc_span::{DUMMY_SP, Span, Symbol};
use rustc_symbol_mangling::mangle_internal_symbol;
use rustc_target::spec::{HasTargetSpec, RelocModel, SmallDataThresholdSupport, Target, TlsModel};
use smallvec::SmallVec;
@ -119,7 +119,7 @@ pub(crate) struct FullCx<'ll, 'tcx> {
/// Statics that will be placed in the llvm.compiler.used variable
/// See <https://llvm.org/docs/LangRef.html#the-llvm-compiler-used-global-variable> for details
pub compiler_used_statics: Vec<&'ll Value>,
pub compiler_used_statics: RefCell<Vec<&'ll Value>>,
/// Mapping of non-scalar types to llvm types.
pub type_lowering: RefCell<FxHashMap<(Ty<'tcx>, Option<VariantIdx>), &'ll Type>>,
@ -146,6 +146,15 @@ pub(crate) struct FullCx<'ll, 'tcx> {
/// `global_asm!` needs to be able to find this new global so that it can
/// compute the correct mangled symbol name to insert into the asm.
pub renamed_statics: RefCell<FxHashMap<DefId, &'ll Value>>,
/// Cached Objective-C class type
pub objc_class_t: Cell<Option<&'ll Type>>,
/// Cache of Objective-C class references
pub objc_classrefs: RefCell<FxHashMap<Symbol, &'ll Value>>,
/// Cache of Objective-C selector references
pub objc_selrefs: RefCell<FxHashMap<Symbol, &'ll Value>>,
}
fn to_llvm_tls_model(tls_model: TlsModel) -> llvm::ThreadLocalMode {
@ -172,35 +181,6 @@ pub(crate) unsafe fn create_module<'ll>(
let mut target_data_layout = sess.target.data_layout.to_string();
let llvm_version = llvm_util::get_version();
if llvm_version < (20, 0, 0) {
if sess.target.arch == "aarch64" || sess.target.arch.starts_with("arm64") {
// LLVM 20 defines three additional address spaces for alternate
// pointer kinds used in Windows.
// See https://github.com/llvm/llvm-project/pull/111879
target_data_layout =
target_data_layout.replace("-p270:32:32-p271:32:32-p272:64:64", "");
}
if sess.target.arch.starts_with("sparc") {
// LLVM 20 updates the sparc layout to correctly align 128 bit integers to 128 bit.
// See https://github.com/llvm/llvm-project/pull/106951
target_data_layout = target_data_layout.replace("-i128:128", "");
}
if sess.target.arch.starts_with("mips64") {
// LLVM 20 updates the mips64 layout to correctly align 128 bit integers to 128 bit.
// See https://github.com/llvm/llvm-project/pull/112084
target_data_layout = target_data_layout.replace("-i128:128", "");
}
if sess.target.arch.starts_with("powerpc64") {
// LLVM 20 updates the powerpc64 layout to correctly align 128 bit integers to 128 bit.
// See https://github.com/llvm/llvm-project/pull/118004
target_data_layout = target_data_layout.replace("-i128:128", "");
}
if sess.target.arch.starts_with("wasm32") || sess.target.arch.starts_with("wasm64") {
// LLVM 20 updates the wasm(32|64) layout to correctly align 128 bit integers to 128 bit.
// See https://github.com/llvm/llvm-project/pull/119204
target_data_layout = target_data_layout.replace("-i128:128", "");
}
}
if llvm_version < (21, 0, 0) {
if sess.target.arch == "nvptx64" {
// LLVM 21 updated the default layout on nvptx: https://github.com/llvm/llvm-project/pull/124961
@ -644,7 +624,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
const_globals: Default::default(),
statics_to_rauw: RefCell::new(Vec::new()),
used_statics: Vec::new(),
compiler_used_statics: Vec::new(),
compiler_used_statics: Default::default(),
type_lowering: Default::default(),
scalar_lltypes: Default::default(),
coverage_cx,
@ -655,6 +635,9 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
intrinsics: Default::default(),
local_gen_sym_counter: Cell::new(0),
renamed_statics: Default::default(),
objc_class_t: Cell::new(None),
objc_classrefs: Default::default(),
objc_selrefs: Default::default(),
},
PhantomData,
)
@ -679,6 +662,69 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
llvm::set_linkage(g, llvm::Linkage::AppendingLinkage);
llvm::set_section(g, c"llvm.metadata");
}
/// The Objective-C ABI that is used.
///
/// This corresponds to the `-fobjc-abi-version=` flag in Clang / GCC.
pub(crate) fn objc_abi_version(&self) -> u32 {
assert!(self.tcx.sess.target.is_like_darwin);
if self.tcx.sess.target.arch == "x86" && self.tcx.sess.target.os == "macos" {
// 32-bit x86 macOS uses ABI version 1 (a.k.a. the "fragile ABI").
1
} else {
// All other Darwin-like targets we support use ABI version 2
// (a.k.a the "non-fragile ABI").
2
}
}
// We do our best here to match what Clang does when compiling Objective-C natively.
// See Clang's `CGObjCCommonMac::EmitImageInfo`:
// https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L5085
pub(crate) fn add_objc_module_flags(&self) {
let abi_version = self.objc_abi_version();
llvm::add_module_flag_u32(
self.llmod,
llvm::ModuleFlagMergeBehavior::Error,
"Objective-C Version",
abi_version,
);
llvm::add_module_flag_u32(
self.llmod,
llvm::ModuleFlagMergeBehavior::Error,
"Objective-C Image Info Version",
0,
);
llvm::add_module_flag_str(
self.llmod,
llvm::ModuleFlagMergeBehavior::Error,
"Objective-C Image Info Section",
match abi_version {
1 => "__OBJC,__image_info,regular",
2 => "__DATA,__objc_imageinfo,regular,no_dead_strip",
_ => unreachable!(),
},
);
if self.tcx.sess.target.env == "sim" {
llvm::add_module_flag_u32(
self.llmod,
llvm::ModuleFlagMergeBehavior::Error,
"Objective-C Is Simulated",
1 << 5,
);
}
llvm::add_module_flag_u32(
self.llmod,
llvm::ModuleFlagMergeBehavior::Error,
"Objective-C Class Properties",
1 << 6,
);
}
}
impl<'ll> SimpleCx<'ll> {
pub(crate) fn get_type_of_global(&self, val: &'ll Value) -> &'ll Type {

View file

@ -32,9 +32,7 @@ use self::type_map::{DINodeCreationResult, Stub, UniqueTypeId};
use super::CodegenUnitDebugContext;
use super::namespace::mangled_name_of_instance;
use super::type_names::{compute_debuginfo_type_name, compute_debuginfo_vtable_name};
use super::utils::{
DIB, create_DIArray, debug_context, get_namespace_for_item, is_node_local_to_unit,
};
use super::utils::{DIB, debug_context, get_namespace_for_item, is_node_local_to_unit};
use crate::common::{AsCCharPtr, CodegenCx};
use crate::debuginfo::dwarf_const;
use crate::debuginfo::metadata::type_map::build_type_with_children;
@ -103,32 +101,33 @@ fn build_fixed_size_array_di_node<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
unique_type_id: UniqueTypeId<'tcx>,
array_type: Ty<'tcx>,
span: Span,
) -> DINodeCreationResult<'ll> {
let ty::Array(element_type, len) = array_type.kind() else {
bug!("build_fixed_size_array_di_node() called with non-ty::Array type `{:?}`", array_type)
};
let element_type_di_node = type_di_node(cx, *element_type);
let element_type_di_node = spanned_type_di_node(cx, *element_type, span);
return_if_di_node_created_in_meantime!(cx, unique_type_id);
let (size, align) = cx.size_and_align_of(array_type);
let (size, align) = cx.spanned_size_and_align_of(array_type, span);
let upper_bound = len
.try_to_target_usize(cx.tcx)
.expect("expected monomorphic const in codegen") as c_longlong;
let subrange =
unsafe { Some(llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound)) };
let subrange = unsafe { llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound) };
let subscripts = &[subrange];
let subscripts = create_DIArray(DIB(cx), &[subrange]);
let di_node = unsafe {
llvm::LLVMRustDIBuilderCreateArrayType(
llvm::LLVMDIBuilderCreateArrayType(
DIB(cx),
size.bits(),
align.bits() as u32,
element_type_di_node,
subscripts,
subscripts.as_ptr(),
subscripts.len() as c_uint,
)
};
@ -174,17 +173,13 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
"ptr_type={ptr_type}, pointee_type={pointee_type}",
);
let di_node = unsafe {
llvm::LLVMRustDIBuilderCreatePointerType(
DIB(cx),
pointee_type_di_node,
pointer_size.bits(),
pointer_align.abi.bits() as u32,
0, // Ignore DWARF address space.
ptr_type_debuginfo_name.as_c_char_ptr(),
ptr_type_debuginfo_name.len(),
)
};
let di_node = create_pointer_type(
cx,
pointee_type_di_node,
pointer_size,
pointer_align.abi,
&ptr_type_debuginfo_name,
);
DINodeCreationResult { di_node, already_stored_in_typemap: false }
}
@ -232,17 +227,13 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
// The data pointer type is a regular, thin pointer, regardless of whether this
// is a slice or a trait object.
let data_ptr_type_di_node = unsafe {
llvm::LLVMRustDIBuilderCreatePointerType(
DIB(cx),
pointee_type_di_node,
addr_field.size.bits(),
addr_field.align.abi.bits() as u32,
0, // Ignore DWARF address space.
std::ptr::null(),
0,
)
};
let data_ptr_type_di_node = create_pointer_type(
cx,
pointee_type_di_node,
addr_field.size,
addr_field.align.abi,
"",
);
smallvec![
build_field_di_node(
@ -317,7 +308,7 @@ fn build_subroutine_type_di_node<'ll, 'tcx>(
debug_context(cx).type_map.unique_id_to_di_node.borrow_mut().remove(&unique_type_id);
let fn_di_node = create_subroutine_type(cx, create_DIArray(DIB(cx), &signature_di_nodes[..]));
let fn_di_node = create_subroutine_type(cx, &signature_di_nodes[..]);
// This is actually a function pointer, so wrap it in pointer DI.
let name = compute_debuginfo_type_name(cx.tcx, fn_ty, false);
@ -328,26 +319,44 @@ fn build_subroutine_type_di_node<'ll, 'tcx>(
}
_ => unreachable!(),
};
let di_node = unsafe {
llvm::LLVMRustDIBuilderCreatePointerType(
DIB(cx),
fn_di_node,
size.bits(),
align.bits() as u32,
0, // Ignore DWARF address space.
name.as_c_char_ptr(),
name.len(),
)
};
let di_node = create_pointer_type(cx, fn_di_node, size, align, &name);
DINodeCreationResult::new(di_node, false)
}
pub(super) fn create_subroutine_type<'ll>(
cx: &CodegenCx<'ll, '_>,
signature: &'ll DICompositeType,
signature: &[Option<&'ll llvm::Metadata>],
) -> &'ll DICompositeType {
unsafe { llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(cx), signature) }
unsafe {
llvm::LLVMDIBuilderCreateSubroutineType(
DIB(cx),
None, // ("File" is ignored and has no effect)
signature.as_ptr(),
signature.len() as c_uint,
DIFlags::FlagZero, // (default value)
)
}
}
fn create_pointer_type<'ll>(
cx: &CodegenCx<'ll, '_>,
pointee_ty: &'ll llvm::Metadata,
size: Size,
align: Align,
name: &str,
) -> &'ll llvm::Metadata {
unsafe {
llvm::LLVMDIBuilderCreatePointerType(
DIB(cx),
pointee_ty,
size.bits(),
align.bits() as u32,
0, // Ignore DWARF address space.
name.as_ptr(),
name.len(),
)
}
}
/// Create debuginfo for `dyn SomeTrait` types. Currently these are empty structs
@ -447,7 +456,7 @@ pub(crate) fn spanned_type_di_node<'ll, 'tcx>(
build_basic_type_di_node(cx, t)
}
ty::Tuple(elements) if elements.is_empty() => build_basic_type_di_node(cx, t),
ty::Array(..) => build_fixed_size_array_di_node(cx, unique_type_id, t),
ty::Array(..) => build_fixed_size_array_di_node(cx, unique_type_id, t, span),
ty::Slice(_) | ty::Str => build_slice_type_di_node(cx, t, unique_type_id),
ty::Dynamic(..) => build_dyn_type_di_node(cx, t, unique_type_id),
ty::Foreign(..) => build_foreign_type_di_node(cx, t, unique_type_id),
@ -812,14 +821,15 @@ fn build_basic_type_di_node<'ll, 'tcx>(
};
let typedef_di_node = unsafe {
llvm::LLVMRustDIBuilderCreateTypedef(
llvm::LLVMDIBuilderCreateTypedef(
DIB(cx),
ty_di_node,
typedef_name.as_c_char_ptr(),
typedef_name.as_ptr(),
typedef_name.len(),
unknown_file_metadata(cx),
0,
None,
0, // (no line number)
None, // (no scope)
0u32, // (no alignment specified)
)
};
@ -833,12 +843,13 @@ fn create_basic_type<'ll, 'tcx>(
encoding: u32,
) -> &'ll DIBasicType {
unsafe {
llvm::LLVMRustDIBuilderCreateBasicType(
llvm::LLVMDIBuilderCreateBasicType(
DIB(cx),
name.as_c_char_ptr(),
name.as_ptr(),
name.len(),
size.bits(),
encoding,
DIFlags::FlagZero,
)
}
}
@ -1024,10 +1035,10 @@ fn create_member_type<'ll, 'tcx>(
type_di_node: &'ll DIType,
) -> &'ll DIType {
unsafe {
llvm::LLVMRustDIBuilderCreateMemberType(
llvm::LLVMDIBuilderCreateMemberType(
DIB(cx),
owner,
name.as_c_char_ptr(),
name.as_ptr(),
name.len(),
file_metadata,
line_number,
@ -1435,7 +1446,7 @@ fn build_vtable_type_di_node<'ll, 'tcx>(
let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref {
let trait_ref = poly_trait_ref.with_self_ty(tcx, ty);
let trait_ref = tcx.erase_regions(trait_ref);
let trait_ref = tcx.erase_and_anonymize_regions(trait_ref);
tcx.vtable_entries(trait_ref)
} else {
@ -1562,7 +1573,7 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>(
// Unwrap potential addrspacecast
let vtable = find_vtable_behind_cast(vtable);
let trait_ref_self = trait_ref.with_self_ty(cx.tcx, ty);
let trait_ref_self = cx.tcx.erase_regions(trait_ref_self);
let trait_ref_self = cx.tcx.erase_and_anonymize_regions(trait_ref_self);
let trait_def_id = trait_ref_self.def_id;
let trait_vis = cx.tcx.visibility(trait_def_id);

View file

@ -11,7 +11,7 @@ use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, AdtDef, CoroutineArgs, CoroutineArgsExt, Ty};
use smallvec::smallvec;
use crate::common::{AsCCharPtr, CodegenCx};
use crate::common::CodegenCx;
use crate::debuginfo::dwarf_const::DW_TAG_const_type;
use crate::debuginfo::metadata::enums::DiscrResult;
use crate::debuginfo::metadata::type_map::{self, Stub, UniqueTypeId};
@ -378,20 +378,17 @@ fn build_single_variant_union_fields<'ll, 'tcx>(
variant_struct_type_wrapper_di_node,
None,
),
unsafe {
llvm::LLVMRustDIBuilderCreateStaticMemberType(
DIB(cx),
enum_type_di_node,
TAG_FIELD_NAME.as_c_char_ptr(),
TAG_FIELD_NAME.len(),
unknown_file_metadata(cx),
UNKNOWN_LINE_NUMBER,
variant_names_type_di_node,
visibility_flags,
Some(cx.const_u64(SINGLE_VARIANT_VIRTUAL_DISR)),
tag_base_type_align.bits() as u32,
)
}
create_static_member_type(
cx,
enum_type_di_node,
TAG_FIELD_NAME,
unknown_file_metadata(cx),
UNKNOWN_LINE_NUMBER,
variant_names_type_di_node,
visibility_flags,
Some(cx.const_u64(SINGLE_VARIANT_VIRTUAL_DISR)),
tag_base_type_align,
),
]
}
@ -570,27 +567,28 @@ fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>(
let build_assoc_const = |name: &str,
type_di_node_: &'ll DIType,
value: u64,
align: Align| unsafe {
align: Align|
-> &'ll llvm::Metadata {
// FIXME: Currently we force all DISCR_* values to be u64's as LLDB seems to have
// problems inspecting other value types. Since DISCR_* is typically only going to be
// directly inspected via the debugger visualizer - which compares it to the `tag` value
// (whose type is not modified at all) it shouldn't cause any real problems.
let (t_di, align) = if name == ASSOC_CONST_DISCR_NAME {
(type_di_node_, align.bits() as u32)
(type_di_node_, align)
} else {
let ty_u64 = Ty::new_uint(cx.tcx, ty::UintTy::U64);
(type_di_node(cx, ty_u64), Align::EIGHT.bits() as u32)
(type_di_node(cx, ty_u64), Align::EIGHT)
};
// must wrap type in a `const` modifier for LLDB to be able to inspect the value of the member
let field_type =
llvm::LLVMRustDIBuilderCreateQualifiedType(DIB(cx), DW_TAG_const_type, t_di);
let field_type = unsafe {
llvm::LLVMDIBuilderCreateQualifiedType(DIB(cx), DW_TAG_const_type, t_di)
};
llvm::LLVMRustDIBuilderCreateStaticMemberType(
DIB(cx),
create_static_member_type(
cx,
wrapper_struct_type_di_node,
name.as_c_char_ptr(),
name.len(),
name,
unknown_file_metadata(cx),
UNKNOWN_LINE_NUMBER,
field_type,
@ -975,3 +973,30 @@ fn variant_struct_wrapper_type_name(variant_index: VariantIdx) -> Cow<'static, s
.map(|&s| Cow::from(s))
.unwrap_or_else(|| format!("Variant{}", variant_index.as_usize()).into())
}
fn create_static_member_type<'ll>(
cx: &CodegenCx<'ll, '_>,
scope: &'ll llvm::Metadata,
name: &str,
file: &'ll llvm::Metadata,
line_number: c_uint,
ty: &'ll llvm::Metadata,
flags: DIFlags,
value: Option<&'ll llvm::Value>,
align: Align,
) -> &'ll llvm::Metadata {
unsafe {
llvm::LLVMDIBuilderCreateStaticMemberType(
DIB(cx),
scope,
name.as_ptr(),
name.len(),
file,
line_number,
ty,
flags,
value,
align.bits() as c_uint,
)
}
}

View file

@ -1,5 +1,6 @@
use std::cell::RefCell;
use libc::c_uint;
use rustc_abi::{Align, Size, VariantIdx};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
@ -9,7 +10,7 @@ use rustc_middle::bug;
use rustc_middle::ty::{self, ExistentialTraitRef, Ty, TyCtxt};
use super::{DefinitionLocation, SmallVec, UNKNOWN_LINE_NUMBER, unknown_file_metadata};
use crate::common::{AsCCharPtr, CodegenCx};
use crate::common::CodegenCx;
use crate::debuginfo::utils::{DIB, create_DIArray, debug_context};
use crate::llvm::debuginfo::{DIFlags, DIScope, DIType};
use crate::llvm::{self};
@ -191,7 +192,7 @@ pub(super) fn stub<'ll, 'tcx>(
containing_scope: Option<&'ll DIScope>,
flags: DIFlags,
) -> StubInfo<'ll, 'tcx> {
let empty_array = create_DIArray(DIB(cx), &[]);
let no_elements: &[Option<&llvm::Metadata>] = &[];
let unique_type_id_str = unique_type_id.generate_unique_id_string(cx.tcx);
let (file_metadata, line_number) = if let Some(def_location) = def_location {
@ -207,10 +208,10 @@ pub(super) fn stub<'ll, 'tcx>(
_ => None,
};
unsafe {
llvm::LLVMRustDIBuilderCreateStructType(
llvm::LLVMDIBuilderCreateStructType(
DIB(cx),
containing_scope,
name.as_c_char_ptr(),
name.as_ptr(),
name.len(),
file_metadata,
line_number,
@ -218,28 +219,30 @@ pub(super) fn stub<'ll, 'tcx>(
align.bits() as u32,
flags,
None,
empty_array,
0,
no_elements.as_ptr(),
no_elements.len() as c_uint,
0u32, // (Objective-C runtime version; default is 0)
vtable_holder,
unique_type_id_str.as_c_char_ptr(),
unique_type_id_str.as_ptr(),
unique_type_id_str.len(),
)
}
}
Stub::Union => unsafe {
llvm::LLVMRustDIBuilderCreateUnionType(
llvm::LLVMDIBuilderCreateUnionType(
DIB(cx),
containing_scope,
name.as_c_char_ptr(),
name.as_ptr(),
name.len(),
file_metadata,
line_number,
size.bits(),
align.bits() as u32,
flags,
Some(empty_array),
0,
unique_type_id_str.as_c_char_ptr(),
no_elements.as_ptr(),
no_elements.len() as c_uint,
0u32, // (Objective-C runtime version; default is 0)
unique_type_id_str.as_ptr(),
unique_type_id_str.len(),
)
},

View file

@ -349,7 +349,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
let file_metadata = file_metadata(self, &loc.file);
let function_type_metadata =
create_subroutine_type(self, get_function_signature(self, fn_abi));
create_subroutine_type(self, &get_function_signature(self, fn_abi));
let mut name = String::with_capacity(64);
type_names::push_item_name(tcx, def_id, false, &mut name);
@ -441,9 +441,9 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
fn get_function_signature<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
) -> &'ll DIArray {
) -> Vec<Option<&'ll llvm::Metadata>> {
if cx.sess().opts.debuginfo != DebugInfo::Full {
return create_DIArray(DIB(cx), &[]);
return vec![];
}
let mut signature = Vec::with_capacity(fn_abi.args.len() + 1);
@ -484,7 +484,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
.extend(fn_abi.args.iter().map(|arg| Some(type_di_node(cx, arg.layout.ty))));
}
create_DIArray(DIB(cx), &signature[..])
signature
}
fn get_template_parameters<'ll, 'tcx>(

View file

@ -1208,7 +1208,8 @@ fn codegen_autodiff<'ll, 'tcx>(
adjust_activity_to_abi(
tcx,
fn_source.ty(tcx, TypingEnv::fully_monomorphized()),
fn_source,
TypingEnv::fully_monomorphized(),
&mut diff_attrs.input_activity,
);

View file

@ -45,6 +45,7 @@ use rustc_middle::util::Providers;
use rustc_session::Session;
use rustc_session::config::{OptLevel, OutputFilenames, PrintKind, PrintRequest};
use rustc_span::Symbol;
use rustc_target::spec::{RelocModel, TlsModel};
mod abi;
mod allocator;
@ -244,16 +245,7 @@ impl CodegenBackend for LlvmCodegenBackend {
match req.kind {
PrintKind::RelocationModels => {
writeln!(out, "Available relocation models:").unwrap();
for name in &[
"static",
"pic",
"pie",
"dynamic-no-pic",
"ropi",
"rwpi",
"ropi-rwpi",
"default",
] {
for name in RelocModel::ALL.iter().map(RelocModel::desc).chain(["default"]) {
writeln!(out, " {name}").unwrap();
}
writeln!(out).unwrap();
@ -267,9 +259,7 @@ impl CodegenBackend for LlvmCodegenBackend {
}
PrintKind::TlsModels => {
writeln!(out, "Available TLS models:").unwrap();
for name in
&["global-dynamic", "local-dynamic", "initial-exec", "local-exec", "emulated"]
{
for name in TlsModel::ALL.iter().map(TlsModel::desc) {
writeln!(out, " {name}").unwrap();
}
writeln!(out).unwrap();

View file

@ -59,10 +59,10 @@ pub(crate) enum LLVMRustVerifierFailureAction {
LLVMReturnStatusAction = 2,
}
#[cfg(llvm_enzyme)]
#[cfg(feature = "llvm_enzyme")]
pub(crate) use self::Enzyme_AD::*;
#[cfg(llvm_enzyme)]
#[cfg(feature = "llvm_enzyme")]
pub(crate) mod Enzyme_AD {
use std::ffi::{CString, c_char};
@ -134,10 +134,10 @@ pub(crate) mod Enzyme_AD {
}
}
#[cfg(not(llvm_enzyme))]
#[cfg(not(feature = "llvm_enzyme"))]
pub(crate) use self::Fallback_AD::*;
#[cfg(not(llvm_enzyme))]
#[cfg(not(feature = "llvm_enzyme"))]
pub(crate) mod Fallback_AD {
#![allow(unused_variables)]

View file

@ -24,9 +24,9 @@ use rustc_target::spec::SymbolVisibility;
use super::RustString;
use super::debuginfo::{
DIArray, DIBasicType, DIBuilder, DICompositeType, DIDerivedType, DIDescriptor, DIEnumerator,
DIFile, DIFlags, DIGlobalVariableExpression, DILocation, DISPFlags, DIScope, DISubprogram,
DISubrange, DITemplateTypeParameter, DIType, DIVariable, DebugEmissionKind, DebugNameTableKind,
DIArray, DIBuilder, DIDerivedType, DIDescriptor, DIEnumerator, DIFile, DIFlags,
DIGlobalVariableExpression, DILocation, DISPFlags, DIScope, DISubprogram, DISubrange,
DITemplateTypeParameter, DIType, DIVariable, DebugEmissionKind, DebugNameTableKind,
};
use crate::llvm;
@ -1237,6 +1237,7 @@ unsafe extern "C" {
pub(crate) safe fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool);
pub(crate) safe fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool);
pub(crate) safe fn LLVMSetTailCallKind(CallInst: &Value, kind: TailCallKind);
pub(crate) safe fn LLVMSetExternallyInitialized(GlobalVar: &Value, IsExtInit: Bool);
// Operations on attributes
pub(crate) fn LLVMCreateStringAttribute(
@ -1870,6 +1871,124 @@ unsafe extern "C" {
Scope: &'ll Metadata,
InlinedAt: Option<&'ll Metadata>,
) -> &'ll Metadata;
pub(crate) fn LLVMDIBuilderCreateSubroutineType<'ll>(
Builder: &DIBuilder<'ll>,
File: Option<&'ll Metadata>, // (ignored and has no effect)
ParameterTypes: *const Option<&'ll Metadata>,
NumParameterTypes: c_uint,
Flags: DIFlags, // (default is `DIFlags::DIFlagZero`)
) -> &'ll Metadata;
pub(crate) fn LLVMDIBuilderCreateUnionType<'ll>(
Builder: &DIBuilder<'ll>,
Scope: Option<&'ll Metadata>,
Name: *const c_uchar, // See "PTR_LEN_STR".
NameLen: size_t,
File: &'ll Metadata,
LineNumber: c_uint,
SizeInBits: u64,
AlignInBits: u32,
Flags: DIFlags,
Elements: *const Option<&'ll Metadata>,
NumElements: c_uint,
RunTimeLang: c_uint, // (optional Objective-C runtime version; default is 0)
UniqueId: *const c_uchar, // See "PTR_LEN_STR".
UniqueIdLen: size_t,
) -> &'ll Metadata;
pub(crate) fn LLVMDIBuilderCreateArrayType<'ll>(
Builder: &DIBuilder<'ll>,
Size: u64,
Align: u32,
Ty: &'ll Metadata,
Subscripts: *const &'ll Metadata,
NumSubscripts: c_uint,
) -> &'ll Metadata;
pub(crate) fn LLVMDIBuilderCreateBasicType<'ll>(
Builder: &DIBuilder<'ll>,
Name: *const c_uchar, // See "PTR_LEN_STR".
NameLen: size_t,
SizeInBits: u64,
Encoding: c_uint, // (`LLVMDWARFTypeEncoding`)
Flags: DIFlags, // (default is `DIFlags::DIFlagZero`)
) -> &'ll Metadata;
pub(crate) fn LLVMDIBuilderCreatePointerType<'ll>(
Builder: &DIBuilder<'ll>,
PointeeTy: &'ll Metadata,
SizeInBits: u64,
AlignInBits: u32,
AddressSpace: c_uint, // (optional DWARF address space; default is 0)
Name: *const c_uchar, // See "PTR_LEN_STR".
NameLen: size_t,
) -> &'ll Metadata;
pub(crate) fn LLVMDIBuilderCreateStructType<'ll>(
Builder: &DIBuilder<'ll>,
Scope: Option<&'ll Metadata>,
Name: *const c_uchar, // See "PTR_LEN_STR".
NameLen: size_t,
File: &'ll Metadata,
LineNumber: c_uint,
SizeInBits: u64,
AlignInBits: u32,
Flags: DIFlags,
DerivedFrom: Option<&'ll Metadata>,
Elements: *const Option<&'ll Metadata>,
NumElements: c_uint,
RunTimeLang: c_uint, // (optional Objective-C runtime version; default is 0)
VTableHolder: Option<&'ll Metadata>,
UniqueId: *const c_uchar, // See "PTR_LEN_STR".
UniqueIdLen: size_t,
) -> &'ll Metadata;
pub(crate) fn LLVMDIBuilderCreateMemberType<'ll>(
Builder: &DIBuilder<'ll>,
Scope: &'ll Metadata,
Name: *const c_uchar, // See "PTR_LEN_STR".
NameLen: size_t,
File: &'ll Metadata,
LineNo: c_uint,
SizeInBits: u64,
AlignInBits: u32,
OffsetInBits: u64,
Flags: DIFlags,
Ty: &'ll Metadata,
) -> &'ll Metadata;
pub(crate) fn LLVMDIBuilderCreateStaticMemberType<'ll>(
Builder: &DIBuilder<'ll>,
Scope: &'ll Metadata,
Name: *const c_uchar, // See "PTR_LEN_STR".
NameLen: size_t,
File: &'ll Metadata,
LineNumber: c_uint,
Type: &'ll Metadata,
Flags: DIFlags,
ConstantVal: Option<&'ll Value>,
AlignInBits: u32,
) -> &'ll Metadata;
/// Creates a "qualified type" in the C/C++ sense, by adding modifiers
/// like `const` or `volatile`.
pub(crate) fn LLVMDIBuilderCreateQualifiedType<'ll>(
Builder: &DIBuilder<'ll>,
Tag: c_uint, // (DWARF tag, e.g. `DW_TAG_const_type`)
Type: &'ll Metadata,
) -> &'ll Metadata;
pub(crate) fn LLVMDIBuilderCreateTypedef<'ll>(
Builder: &DIBuilder<'ll>,
Type: &'ll Metadata,
Name: *const c_uchar, // See "PTR_LEN_STR".
NameLen: size_t,
File: &'ll Metadata,
LineNo: c_uint,
Scope: Option<&'ll Metadata>,
AlignInBits: u32, // (optional; default is 0)
) -> &'ll Metadata;
}
#[link(name = "llvm-wrapper", kind = "static")]
@ -2172,11 +2291,6 @@ unsafe extern "C" {
SourceLen: size_t,
) -> &'a DIFile;
pub(crate) fn LLVMRustDIBuilderCreateSubroutineType<'a>(
Builder: &DIBuilder<'a>,
ParameterTypes: &'a DIArray,
) -> &'a DICompositeType;
pub(crate) fn LLVMRustDIBuilderCreateFunction<'a>(
Builder: &DIBuilder<'a>,
Scope: &'a DIDescriptor,
@ -2210,66 +2324,6 @@ unsafe extern "C" {
TParam: &'a DIArray,
) -> &'a DISubprogram;
pub(crate) fn LLVMRustDIBuilderCreateBasicType<'a>(
Builder: &DIBuilder<'a>,
Name: *const c_char,
NameLen: size_t,
SizeInBits: u64,
Encoding: c_uint,
) -> &'a DIBasicType;
pub(crate) fn LLVMRustDIBuilderCreateTypedef<'a>(
Builder: &DIBuilder<'a>,
Type: &'a DIBasicType,
Name: *const c_char,
NameLen: size_t,
File: &'a DIFile,
LineNo: c_uint,
Scope: Option<&'a DIScope>,
) -> &'a DIDerivedType;
pub(crate) fn LLVMRustDIBuilderCreatePointerType<'a>(
Builder: &DIBuilder<'a>,
PointeeTy: &'a DIType,
SizeInBits: u64,
AlignInBits: u32,
AddressSpace: c_uint,
Name: *const c_char,
NameLen: size_t,
) -> &'a DIDerivedType;
pub(crate) fn LLVMRustDIBuilderCreateStructType<'a>(
Builder: &DIBuilder<'a>,
Scope: Option<&'a DIDescriptor>,
Name: *const c_char,
NameLen: size_t,
File: &'a DIFile,
LineNumber: c_uint,
SizeInBits: u64,
AlignInBits: u32,
Flags: DIFlags,
DerivedFrom: Option<&'a DIType>,
Elements: &'a DIArray,
RunTimeLang: c_uint,
VTableHolder: Option<&'a DIType>,
UniqueId: *const c_char,
UniqueIdLen: size_t,
) -> &'a DICompositeType;
pub(crate) fn LLVMRustDIBuilderCreateMemberType<'a>(
Builder: &DIBuilder<'a>,
Scope: &'a DIDescriptor,
Name: *const c_char,
NameLen: size_t,
File: &'a DIFile,
LineNo: c_uint,
SizeInBits: u64,
AlignInBits: u32,
OffsetInBits: u64,
Flags: DIFlags,
Ty: &'a DIType,
) -> &'a DIDerivedType;
pub(crate) fn LLVMRustDIBuilderCreateVariantMemberType<'a>(
Builder: &DIBuilder<'a>,
Scope: &'a DIScope,
@ -2285,25 +2339,6 @@ unsafe extern "C" {
Ty: &'a DIType,
) -> &'a DIType;
pub(crate) fn LLVMRustDIBuilderCreateStaticMemberType<'a>(
Builder: &DIBuilder<'a>,
Scope: &'a DIDescriptor,
Name: *const c_char,
NameLen: size_t,
File: &'a DIFile,
LineNo: c_uint,
Ty: &'a DIType,
Flags: DIFlags,
val: Option<&'a Value>,
AlignInBits: u32,
) -> &'a DIDerivedType;
pub(crate) fn LLVMRustDIBuilderCreateQualifiedType<'a>(
Builder: &DIBuilder<'a>,
Tag: c_uint,
Type: &'a DIType,
) -> &'a DIDerivedType;
pub(crate) fn LLVMRustDIBuilderCreateStaticVariable<'a>(
Builder: &DIBuilder<'a>,
Context: Option<&'a DIScope>,
@ -2335,14 +2370,6 @@ unsafe extern "C" {
AlignInBits: u32,
) -> &'a DIVariable;
pub(crate) fn LLVMRustDIBuilderCreateArrayType<'a>(
Builder: &DIBuilder<'a>,
Size: u64,
AlignInBits: u32,
Ty: &'a DIType,
Subscripts: &'a DIArray,
) -> &'a DIType;
pub(crate) fn LLVMRustDIBuilderGetOrCreateSubrange<'a>(
Builder: &DIBuilder<'a>,
Lo: i64,
@ -2388,22 +2415,6 @@ unsafe extern "C" {
IsScoped: bool,
) -> &'a DIType;
pub(crate) fn LLVMRustDIBuilderCreateUnionType<'a>(
Builder: &DIBuilder<'a>,
Scope: Option<&'a DIScope>,
Name: *const c_char,
NameLen: size_t,
File: &'a DIFile,
LineNumber: c_uint,
SizeInBits: u64,
AlignInBits: u32,
Flags: DIFlags,
Elements: Option<&'a DIArray>,
RunTimeLang: c_uint,
UniqueId: *const c_char,
UniqueIdLen: size_t,
) -> &'a DIType;
pub(crate) fn LLVMRustDIBuilderCreateVariantPart<'a>(
Builder: &DIBuilder<'a>,
Scope: &'a DIScope,
@ -2480,8 +2491,10 @@ unsafe extern "C" {
OutputObjFile: *const c_char,
DebugInfoCompression: *const c_char,
UseEmulatedTls: bool,
ArgsCstrBuff: *const c_uchar, // See "PTR_LEN_STR".
ArgsCstrBuffLen: usize,
Argv0: *const c_uchar, // See "PTR_LEN_STR".
Argv0Len: size_t,
CommandLineArgs: *const c_uchar, // See "PTR_LEN_STR".
CommandLineArgsLen: size_t,
UseWasmEH: bool,
) -> *mut TargetMachine;

View file

@ -258,6 +258,10 @@ pub(crate) fn set_alignment(llglobal: &Value, align: Align) {
}
}
pub(crate) fn set_externally_initialized(llglobal: &Value, is_ext_init: bool) {
LLVMSetExternallyInitialized(llglobal, is_ext_init.to_llvm_bool());
}
/// Get the `name`d comdat from `llmod` and assign it to `llglobal`.
///
/// Inserts the comdat into `llmod` if it does not exist.

View file

@ -217,27 +217,16 @@ impl<'a> IntoIterator for LLVMFeature<'a> {
/// Rust can also be build with an external precompiled version of LLVM which might lead to failures
/// if the oldest tested / supported LLVM version doesn't yet support the relevant intrinsics.
pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFeature<'a>> {
let arch = if sess.target.arch == "x86_64" {
"x86"
} else if sess.target.arch == "arm64ec" {
"aarch64"
} else if sess.target.arch == "sparc64" {
"sparc"
} else if sess.target.arch == "powerpc64" {
"powerpc"
} else {
&*sess.target.arch
let raw_arch = &*sess.target.arch;
let arch = match raw_arch {
"x86_64" => "x86",
"arm64ec" => "aarch64",
"sparc64" => "sparc",
"powerpc64" => "powerpc",
_ => raw_arch,
};
let (major, _, _) = get_version();
match (arch, s) {
("x86", "sse4.2") => Some(LLVMFeature::with_dependencies(
"sse4.2",
smallvec![TargetFeatureFoldStrength::EnableOnly("crc32")],
)),
("x86", "pclmulqdq") => Some(LLVMFeature::new("pclmul")),
("x86", "rdrand") => Some(LLVMFeature::new("rdrnd")),
("x86", "bmi1") => Some(LLVMFeature::new("bmi")),
("x86", "cmpxchg16b") => Some(LLVMFeature::new("cx16")),
("x86", "lahfsahf") => Some(LLVMFeature::new("sahf")),
("aarch64", "rcpc2") => Some(LLVMFeature::new("rcpc-immo")),
("aarch64", "dpb") => Some(LLVMFeature::new("ccpp")),
("aarch64", "dpb2") => Some(LLVMFeature::new("ccdp")),
@ -246,9 +235,6 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
("aarch64", "pmuv3") => Some(LLVMFeature::new("perfmon")),
("aarch64", "paca") => Some(LLVMFeature::new("pauth")),
("aarch64", "pacg") => Some(LLVMFeature::new("pauth")),
// Before LLVM 20 those two features were packaged together as b16b16
("aarch64", "sve-b16b16") if get_version().0 < 20 => Some(LLVMFeature::new("b16b16")),
("aarch64", "sme-b16b16") if get_version().0 < 20 => Some(LLVMFeature::new("b16b16")),
("aarch64", "flagm2") => Some(LLVMFeature::new("altnzcv")),
// Rust ties fp and neon together.
("aarch64", "neon") => Some(LLVMFeature::with_dependencies(
@ -262,57 +248,26 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
// Filter out features that are not supported by the current LLVM version
("aarch64", "fpmr") => None, // only existed in 18
("arm", "fp16") => Some(LLVMFeature::new("fullfp16")),
// NVPTX targets added in LLVM 20
("nvptx64", "sm_100") if get_version().0 < 20 => None,
("nvptx64", "sm_100a") if get_version().0 < 20 => None,
("nvptx64", "sm_101") if get_version().0 < 20 => None,
("nvptx64", "sm_101a") if get_version().0 < 20 => None,
("nvptx64", "sm_120") if get_version().0 < 20 => None,
("nvptx64", "sm_120a") if get_version().0 < 20 => None,
("nvptx64", "ptx86") if get_version().0 < 20 => None,
("nvptx64", "ptx87") if get_version().0 < 20 => None,
// Filter out features that are not supported by the current LLVM version
("loongarch64", "div32" | "lam-bh" | "lamcas" | "ld-seq-sa" | "scq")
if get_version().0 < 20 =>
{
None
}
("loongarch32" | "loongarch64", "32s") if get_version().0 < 21 => None,
// Filter out features that are not supported by the current LLVM version
("riscv32" | "riscv64", "zacas" | "rva23u64" | "supm") if get_version().0 < 20 => None,
(
"s390x",
"message-security-assist-extension12"
| "concurrent-functions"
| "miscellaneous-extensions-4"
| "vector-enhancements-3"
| "vector-packed-decimal-enhancement-3",
) if get_version().0 < 20 => None,
("loongarch32" | "loongarch64", "32s") if major < 21 => None,
("powerpc", "power8-crypto") => Some(LLVMFeature::new("crypto")),
("sparc", "leoncasa") => Some(LLVMFeature::new("hasleoncasa")),
("x86", "sse4.2") => Some(LLVMFeature::with_dependencies(
"sse4.2",
smallvec![TargetFeatureFoldStrength::EnableOnly("crc32")],
)),
("x86", "pclmulqdq") => Some(LLVMFeature::new("pclmul")),
("x86", "rdrand") => Some(LLVMFeature::new("rdrnd")),
("x86", "bmi1") => Some(LLVMFeature::new("bmi")),
("x86", "cmpxchg16b") => Some(LLVMFeature::new("cx16")),
("x86", "lahfsahf") => Some(LLVMFeature::new("sahf")),
// Enable the evex512 target feature if an avx512 target feature is enabled.
("x86", s) if s.starts_with("avx512") => Some(LLVMFeature::with_dependencies(
s,
smallvec![TargetFeatureFoldStrength::EnableOnly("evex512")],
)),
// Support for `wide-arithmetic` will first land in LLVM 20 as part of
// llvm/llvm-project#111598
("wasm32" | "wasm64", "wide-arithmetic") if get_version() < (20, 0, 0) => None,
("sparc", "leoncasa") => Some(LLVMFeature::new("hasleoncasa")),
// In LLVM 19, there is no `v8plus` feature and `v9` means "SPARC-V9 instruction available and SPARC-V8+ ABI used".
// https://github.com/llvm/llvm-project/blob/llvmorg-19.1.0/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp#L27-L28
// Before LLVM 19, there was no `v8plus` feature and `v9` means "SPARC-V9 instruction available".
// https://github.com/llvm/llvm-project/blob/llvmorg-18.1.0/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp#L26
("sparc", "v8plus") if get_version().0 == 19 => Some(LLVMFeature::new("v9")),
("powerpc", "power8-crypto") => Some(LLVMFeature::new("crypto")),
// These new `amx` variants and `movrs` were introduced in LLVM20
("x86", "amx-avx512" | "amx-fp8" | "amx-movrs" | "amx-tf32" | "amx-transpose")
if get_version().0 < 20 =>
{
None
}
("x86", "movrs") if get_version().0 < 20 => None,
("x86", "avx10.1") => Some(LLVMFeature::new("avx10.1-512")),
("x86", "avx10.2") if get_version().0 < 20 => None,
("x86", "avx10.2") if get_version().0 >= 20 => Some(LLVMFeature::new("avx10.2-512")),
("x86", "avx10.2") => Some(LLVMFeature::new("avx10.2-512")),
("x86", "apxf") => Some(LLVMFeature::with_dependencies(
"egpr",
smallvec![
@ -716,17 +671,7 @@ pub(crate) fn global_llvm_features(
};
// Features implied by an implicit or explicit `--target`.
features.extend(
sess.target
.features
.split(',')
.filter(|v| !v.is_empty())
// Drop +v8plus feature introduced in LLVM 20.
// (Hard-coded target features do not go through `to_llvm_feature` since they already
// are LLVM feature names, hence we need a special case here.)
.filter(|v| *v != "+v8plus" || get_version() >= (20, 0, 0))
.map(String::from),
);
features.extend(sess.target.features.split(',').filter(|v| !v.is_empty()).map(String::from));
if wants_wasm_eh(sess) && sess.panic_strategy() == PanicStrategy::Unwind {
features.push("+exception-handling".into());

View file

@ -7,6 +7,7 @@ use rustc_middle::bug;
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
use rustc_middle::ty::{self, CoroutineArgsExt, Ty, TypeVisitableExt};
use rustc_span::{DUMMY_SP, Span};
use tracing::debug;
use crate::common::*;
@ -149,7 +150,11 @@ impl<'a, 'tcx> CodegenCx<'a, 'tcx> {
}
pub(crate) fn size_and_align_of(&self, ty: Ty<'tcx>) -> (Size, Align) {
let layout = self.layout_of(ty);
self.spanned_size_and_align_of(ty, DUMMY_SP)
}
pub(crate) fn spanned_size_and_align_of(&self, ty: Ty<'tcx>, span: Span) -> (Size, Align) {
let layout = self.spanned_layout_of(ty, span);
(layout.size, layout.align.abi)
}
}
@ -226,7 +231,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
// Make sure lifetimes are erased, to avoid generating distinct LLVM
// types for Rust types that only differ in the choice of lifetimes.
let normal_ty = cx.tcx.erase_regions(self.ty);
let normal_ty = cx.tcx.erase_and_anonymize_regions(self.ty);
let mut defer = None;
let llty = if self.ty != normal_ty {

View file

@ -908,6 +908,21 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
)
}
"aarch64" => emit_aapcs_va_arg(bx, addr, target_ty),
"arm" => {
// Types wider than 16 bytes are not currently supported. Clang has special logic for
// such types, but `VaArgSafe` is not implemented for any type that is this large.
assert!(bx.cx.size_of(target_ty).bytes() <= 16);
emit_ptr_va_arg(
bx,
addr,
target_ty,
PassMode::Direct,
SlotSize::Bytes4,
AllowHigherAlign::Yes,
ForceRightAdjust::No,
)
}
"s390x" => emit_s390x_va_arg(bx, addr, target_ty),
"powerpc" => emit_powerpc_va_arg(bx, addr, target_ty),
"powerpc64" | "powerpc64le" => emit_ptr_va_arg(

View file

@ -9,7 +9,7 @@ ar_archive_writer = "0.5"
bitflags = "2.4.1"
bstr = "1.11.3"
# `cc` updates often break things, so we pin it here. Cargo enforces "max 1 semver-compat version
# per crate", so if you change this, you need to also change it in `rustc_llvm`.
# per crate", so if you change this, you need to also change it in `rustc_llvm` and `rustc_windows_rc`.
cc = "=1.2.16"
itertools = "0.12"
pathdiff = "0.2.0"

View file

@ -8,8 +8,6 @@ codegen_ssa_aix_strip_not_used = using host's `strip` binary to cross-compile to
codegen_ssa_archive_build_failure = failed to build archive at `{$path}`: {$error}
codegen_ssa_autodiff_without_lto = using the autodiff feature requires using fat-lto
codegen_ssa_bare_instruction_set = `#[instruction_set]` requires an argument
codegen_ssa_binary_output_to_tty = option `-o` or `--emit` is used to write binary output type `{$shorthand}` to stdout, but stdout is a tty
@ -31,7 +29,7 @@ codegen_ssa_cpu_required = target requires explicitly specifying a cpu with `-C
codegen_ssa_create_temp_dir = couldn't create a temp dir: {$error}
codegen_ssa_dlltool_fail_import_library =
Dlltool could not create import library with {$dlltool_path} {$dlltool_args}:
dlltool could not create import library with {$dlltool_path} {$dlltool_args}:
{$stdout}
{$stderr}

View file

@ -109,7 +109,7 @@ impl Command {
}
Program::Lld(ref p, flavor) => {
let mut c = process::Command::new(p);
c.arg("-flavor").arg(flavor.as_str());
c.arg("-flavor").arg(flavor.desc());
c
}
};

View file

@ -168,9 +168,7 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
(&ty::Array(_, len), &ty::Slice(_)) => cx.const_usize(
len.try_to_target_usize(cx.tcx()).expect("expected monomorphic const in codegen"),
),
(&ty::Dynamic(data_a, _, src_dyn_kind), &ty::Dynamic(data_b, _, target_dyn_kind))
if src_dyn_kind == target_dyn_kind =>
{
(&ty::Dynamic(data_a, _), &ty::Dynamic(data_b, _)) => {
let old_info =
old_info.expect("unsized_info: missing old info for trait upcasting coercion");
let b_principal_def_id = data_b.principal_def_id();
@ -208,7 +206,7 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
old_info
}
}
(_, ty::Dynamic(data, _, _)) => meth::get_vtable(
(_, ty::Dynamic(data, _)) => meth::get_vtable(
cx,
source,
data.principal()

View file

@ -296,6 +296,12 @@ fn process_builtin_attrs(
AttributeKind::Sanitize { span, .. } => {
interesting_spans.sanitize = Some(*span);
}
AttributeKind::ObjcClass { classname, .. } => {
codegen_fn_attrs.objc_class = Some(*classname);
}
AttributeKind::ObjcSelector { methname, .. } => {
codegen_fn_attrs.objc_selector = Some(*methname);
}
_ => {}
}
}
@ -562,15 +568,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
codegen_fn_attrs
}
/// If the provided DefId is a method in a trait impl, return the DefId of the method prototype.
fn opt_trait_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
let impl_item = tcx.opt_associated_item(def_id)?;
match impl_item.container {
ty::AssocItemContainer::Impl => impl_item.trait_item_def_id,
_ => None,
}
}
fn disabled_sanitizers_for(tcx: TyCtxt<'_>, did: LocalDefId) -> SanitizerSet {
// Backtrack to the crate root.
let mut disabled = match tcx.opt_local_parent(did) {
@ -600,14 +597,15 @@ fn disabled_sanitizers_for(tcx: TyCtxt<'_>, did: LocalDefId) -> SanitizerSet {
/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
/// applied to the method prototype.
fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
let Some(trait_item) = opt_trait_item(tcx, def_id) else { return false };
tcx.codegen_fn_attrs(trait_item).flags.intersects(CodegenFnAttrFlags::TRACK_CALLER)
tcx.trait_item_of(def_id).is_some_and(|id| {
tcx.codegen_fn_attrs(id).flags.intersects(CodegenFnAttrFlags::TRACK_CALLER)
})
}
/// If the provided DefId is a method in a trait impl, return the value of the `#[align]`
/// attribute on the method prototype (if any).
fn inherited_align<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<Align> {
tcx.codegen_fn_attrs(opt_trait_item(tcx, def_id)?).alignment
tcx.codegen_fn_attrs(tcx.trait_item_of(def_id)?).alignment
}
/// We now check the #\[rustc_autodiff\] attributes which we generated from the #[autodiff(...)]

View file

@ -37,10 +37,6 @@ pub(crate) struct CguNotRecorded<'a> {
pub cgu_name: &'a str,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_autodiff_without_lto)]
pub struct AutodiffWithoutLto;
#[derive(Diagnostic)]
#[diag(codegen_ssa_unknown_reuse_kind)]
pub(crate) struct UnknownReuseKind {

View file

@ -78,7 +78,7 @@ fn dyn_trait_in_self<'tcx>(
) -> Option<ty::ExistentialTraitRef<'tcx>> {
for arg in ty.peel_refs().walk() {
if let GenericArgKind::Type(ty) = arg.kind()
&& let ty::Dynamic(data, _, _) = ty.kind()
&& let ty::Dynamic(data, _) = ty.kind()
{
// FIXME(arbitrary_self_types): This is likely broken for receivers which
// have a "non-self" trait objects as a generic argument.

View file

@ -520,7 +520,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
LocalRef::Place(va_list) => {
bx.va_end(va_list.val.llval);
// Explicitly end the lifetime of the `va_list`, this matters for LLVM.
// Explicitly end the lifetime of the `va_list`, improves LLVM codegen.
bx.lifetime_end(va_list.val.llval, va_list.layout.size);
}
_ => bug!("C-variadic function must have a `VaList` place"),
@ -614,7 +614,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let (maybe_null, drop_fn, fn_abi, drop_instance) = match ty.kind() {
// FIXME(eddyb) perhaps move some of this logic into
// `Instance::resolve_drop_in_place`?
ty::Dynamic(_, _, ty::Dyn) => {
ty::Dynamic(_, _) => {
// IN THIS ARM, WE HAVE:
// ty = *mut (dyn Trait)
// which is: exists<T> ( *mut T, Vtable<T: Trait> )

View file

@ -438,6 +438,10 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
if fx.fn_abi.c_variadic && arg_index == fx.fn_abi.args.len() {
let va_list = PlaceRef::alloca(bx, bx.layout_of(arg_ty));
// Explicitly start the lifetime of the `va_list`, improves LLVM codegen.
bx.lifetime_start(va_list.val.llval, va_list.layout.size);
bx.va_start(va_list.val.llval);
return LocalRef::Place(va_list);

View file

@ -228,6 +228,9 @@ fn prefix_and_suffix<'tcx>(
writeln!(begin, "{asm_name}:").unwrap();
writeln!(end).unwrap();
// emit a label starting with `func_end` for `cargo asm` and other tooling that might
// pattern match on assembly generated by LLVM.
writeln!(end, ".Lfunc_end_{asm_name}:").unwrap();
writeln!(end, ".size {asm_name}, . - {asm_name}").unwrap();
writeln!(end, ".popsection").unwrap();
if !arch_suffix.is_empty() {
@ -246,6 +249,7 @@ fn prefix_and_suffix<'tcx>(
writeln!(begin, "{asm_name}:").unwrap();
writeln!(end).unwrap();
writeln!(end, ".Lfunc_end_{asm_name}:").unwrap();
writeln!(end, ".popsection").unwrap();
if !arch_suffix.is_empty() {
writeln!(end, "{}", arch_suffix).unwrap();
@ -263,6 +267,7 @@ fn prefix_and_suffix<'tcx>(
writeln!(begin, "{asm_name}:").unwrap();
writeln!(end).unwrap();
writeln!(end, ".Lfunc_end_{asm_name}:").unwrap();
writeln!(end, ".popsection").unwrap();
if !arch_suffix.is_empty() {
writeln!(end, "{}", arch_suffix).unwrap();
@ -287,6 +292,7 @@ fn prefix_and_suffix<'tcx>(
writeln!(end).unwrap();
// .size is ignored for function symbols, so we can skip it
writeln!(end, "end_function").unwrap();
writeln!(end, ".Lfunc_end_{asm_name}:").unwrap();
}
BinaryFormat::Xcoff => {
// the LLVM XCOFFAsmParser is extremely incomplete and does not implement many of the

View file

@ -1,5 +1,5 @@
use itertools::Itertools as _;
use rustc_abi::{self as abi, FIRST_VARIANT};
use rustc_abi::{self as abi, BackendRepr, FIRST_VARIANT};
use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
@ -7,9 +7,9 @@ use rustc_middle::{bug, mir, span_bug};
use rustc_session::config::OptLevel;
use tracing::{debug, instrument};
use super::FunctionCx;
use super::operand::{OperandRef, OperandRefBuilder, OperandValue};
use super::place::{PlaceRef, PlaceValue, codegen_tag_value};
use super::{FunctionCx, LocalRef};
use crate::common::{IntPredicate, TypeKind};
use crate::traits::*;
use crate::{MemFlags, base};
@ -25,6 +25,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
match *rvalue {
mir::Rvalue::Use(ref operand) => {
let cg_operand = self.codegen_operand(bx, operand);
// Crucially, we do *not* use `OperandValue::Ref` for types with
// `BackendRepr::Scalar | BackendRepr::ScalarPair`. This ensures we match the MIR
// semantics regarding when assignment operators allow overlap of LHS and RHS.
if matches!(
cg_operand.layout.backend_repr,
BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..),
) {
debug_assert!(!matches!(cg_operand.val, OperandValue::Ref(..)));
}
// FIXME: consider not copying constants through stack. (Fixable by codegen'ing
// constants into `OperandValue::Ref`; why dont we do that yet if we dont?)
cg_operand.val.store(bx, dest);
@ -501,14 +510,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
self.codegen_place_to_pointer(bx, place, mk_ptr)
}
mir::Rvalue::Len(place) => {
let size = self.evaluate_array_len(bx, place);
OperandRef {
val: OperandValue::Immediate(size),
layout: bx.cx().layout_of(bx.tcx().types.usize),
}
}
mir::Rvalue::BinaryOp(op_with_overflow, box (ref lhs, ref rhs))
if let Some(op) = op_with_overflow.overflowing_to_wrapping() =>
{
@ -740,21 +741,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}
fn evaluate_array_len(&mut self, bx: &mut Bx, place: mir::Place<'tcx>) -> Bx::Value {
// ZST are passed as operands and require special handling
// because codegen_place() panics if Local is operand.
if let Some(index) = place.as_local()
&& let LocalRef::Operand(op) = self.locals[index]
&& let ty::Array(_, n) = op.layout.ty.kind()
{
let n = n.try_to_target_usize(bx.tcx()).expect("expected monomorphic const in codegen");
return bx.cx().const_usize(n);
}
// use common size calculation for non zero-sized types
let cg_value = self.codegen_place(bx, place.as_ref());
cg_value.len(bx.cx())
}
/// Codegen an `Rvalue::RawPtr` or `Rvalue::Ref`
fn codegen_place_to_pointer(
&mut self,
@ -892,36 +878,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}
mir::BinOp::Cmp => {
use std::cmp::Ordering;
assert!(!is_float);
if let Some(value) = bx.three_way_compare(lhs_ty, lhs, rhs) {
return value;
}
let pred = |op| base::bin_op_to_icmp_predicate(op, is_signed);
if bx.cx().tcx().sess.opts.optimize == OptLevel::No {
// FIXME: This actually generates tighter assembly, and is a classic trick
// <https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign>
// However, as of 2023-11 it optimizes worse in things like derived
// `PartialOrd`, so only use it in debug for now. Once LLVM can handle it
// better (see <https://github.com/llvm/llvm-project/issues/73417>), it'll
// be worth trying it in optimized builds as well.
let is_gt = bx.icmp(pred(mir::BinOp::Gt), lhs, rhs);
let gtext = bx.zext(is_gt, bx.type_i8());
let is_lt = bx.icmp(pred(mir::BinOp::Lt), lhs, rhs);
let ltext = bx.zext(is_lt, bx.type_i8());
bx.unchecked_ssub(gtext, ltext)
} else {
// These operations are those expected by `tests/codegen-llvm/integer-cmp.rs`,
// from <https://github.com/rust-lang/rust/pull/63767>.
let is_lt = bx.icmp(pred(mir::BinOp::Lt), lhs, rhs);
let is_ne = bx.icmp(pred(mir::BinOp::Ne), lhs, rhs);
let ge = bx.select(
is_ne,
bx.cx().const_i8(Ordering::Greater as i8),
bx.cx().const_i8(Ordering::Equal as i8),
);
bx.select(is_lt, bx.cx().const_i8(Ordering::Less as i8), ge)
}
bx.three_way_compare(lhs_ty, lhs, rhs)
}
mir::BinOp::AddWithOverflow
| mir::BinOp::SubWithOverflow

View file

@ -3,6 +3,7 @@ use std::ops::Deref;
use rustc_abi::{Align, Scalar, Size, WrappingRange};
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::mir;
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout};
use rustc_middle::ty::{AtomicOrdering, Instance, Ty};
use rustc_session::config::OptLevel;
@ -405,15 +406,41 @@ pub trait BuilderMethods<'a, 'tcx>:
fn fcmp(&mut self, op: RealPredicate, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
/// Returns `-1` if `lhs < rhs`, `0` if `lhs == rhs`, and `1` if `lhs > rhs`.
// FIXME: Move the default implementation from `codegen_scalar_binop` into this method and
// remove the `Option` return once LLVM 20 is the minimum version.
fn three_way_compare(
&mut self,
_ty: Ty<'tcx>,
_lhs: Self::Value,
_rhs: Self::Value,
) -> Option<Self::Value> {
None
ty: Ty<'tcx>,
lhs: Self::Value,
rhs: Self::Value,
) -> Self::Value {
// FIXME: This implementation was designed around LLVM's ability to optimize, but `cg_llvm`
// overrides this to just use `@llvm.scmp`/`ucmp` since LLVM 20. This default impl should be
// reevaluated with respect to the remaining backends like cg_gcc, whether they might use
// specialized implementations as well, or continue to use a generic implementation here.
use std::cmp::Ordering;
let pred = |op| crate::base::bin_op_to_icmp_predicate(op, ty.is_signed());
if self.cx().sess().opts.optimize == OptLevel::No {
// This actually generates tighter assembly, and is a classic trick:
// <https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign>.
// However, as of 2023-11 it optimized worse in LLVM in things like derived
// `PartialOrd`, so we were only using it in debug. Since LLVM now uses its own
// intrinsics, it may be be worth trying it in optimized builds for other backends.
let is_gt = self.icmp(pred(mir::BinOp::Gt), lhs, rhs);
let gtext = self.zext(is_gt, self.type_i8());
let is_lt = self.icmp(pred(mir::BinOp::Lt), lhs, rhs);
let ltext = self.zext(is_lt, self.type_i8());
self.unchecked_ssub(gtext, ltext)
} else {
// These operations were better optimized by LLVM, before `@llvm.scmp`/`ucmp` in 20.
// See <https://github.com/rust-lang/rust/pull/63767>.
let is_lt = self.icmp(pred(mir::BinOp::Lt), lhs, rhs);
let is_ne = self.icmp(pred(mir::BinOp::Ne), lhs, rhs);
let ge = self.select(
is_ne,
self.cx().const_i8(Ordering::Greater as i8),
self.cx().const_i8(Ordering::Equal as i8),
);
self.select(is_lt, self.cx().const_i8(Ordering::Less as i8), ge)
}
}
fn memcpy(

View file

@ -573,8 +573,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
Rvalue::Use(_)
| Rvalue::CopyForDeref(..)
| Rvalue::Repeat(..)
| Rvalue::Discriminant(..)
| Rvalue::Len(_) => {}
| Rvalue::Discriminant(..) => {}
Rvalue::Aggregate(kind, ..) => {
if let AggregateKind::Coroutine(def_id, ..) = kind.as_ref()

View file

@ -232,9 +232,7 @@ where
Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx))
}
Rvalue::Discriminant(place) | Rvalue::Len(place) => {
in_place::<Q, _>(cx, in_local, place.as_ref())
}
Rvalue::Discriminant(place) => in_place::<Q, _>(cx, in_local, place.as_ref()),
Rvalue::CopyForDeref(place) => in_place::<Q, _>(cx, in_local, place.as_ref()),

View file

@ -197,7 +197,6 @@ where
| mir::Rvalue::CopyForDeref(..)
| mir::Rvalue::ThreadLocalRef(..)
| mir::Rvalue::Repeat(..)
| mir::Rvalue::Len(..)
| mir::Rvalue::BinaryOp(..)
| mir::Rvalue::NullaryOp(..)
| mir::Rvalue::UnaryOp(..)

View file

@ -1,6 +1,7 @@
use rustc_abi::{BackendRepr, FieldIdx, VariantIdx};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId, ValTreeCreationError};
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::layout::{LayoutCx, TyAndLayout};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::{bug, mir};
@ -196,6 +197,7 @@ fn reconstruct_place_meta<'tcx>(
// Traverse the type, and update `last_valtree` as we go.
let tail = tcx.struct_tail_raw(
layout.ty,
&ObligationCause::dummy(),
|ty| ty,
|| {
let branches = last_valtree.unwrap_branch();

View file

@ -658,7 +658,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let val = self.read_immediate(&receiver)?;
break self.ref_to_mplace(&val)?;
}
ty::Dynamic(.., ty::Dyn) => break receiver.assert_mem_place(), // no immediate unsized values
ty::Dynamic(..) => break receiver.assert_mem_place(), // no immediate unsized values
_ => {
// Not there yet, search for the only non-ZST field.
// (The rules for `DispatchFromDyn` ensure there's exactly one such field.)
@ -675,7 +675,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// (For that reason we also cannot use `unpack_dyn_trait`.)
let receiver_tail =
self.tcx.struct_tail_for_codegen(receiver_place.layout.ty, self.typing_env);
let ty::Dynamic(receiver_trait, _, ty::Dyn) = receiver_tail.kind() else {
let ty::Dynamic(receiver_trait, _) = receiver_tail.kind() else {
span_bug!(self.cur_span(), "dynamic call on non-`dyn` type {}", receiver_tail)
};
assert!(receiver_place.layout.is_unsized());
@ -822,7 +822,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// instead we do the virtual call stuff ourselves. It's easier here than in `eval_fn_call`
// since we can just get a place of the underlying type and use `mplace_to_ref`.
let place = match place.layout.ty.kind() {
ty::Dynamic(data, _, ty::Dyn) => {
ty::Dynamic(data, _) => {
// Dropping a trait object. Need to find actual drop fn.
self.unpack_dyn_trait(&place, data)?
}

View file

@ -386,7 +386,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
);
self.write_immediate(val, dest)
}
(ty::Dynamic(data_a, _, ty::Dyn), ty::Dynamic(data_b, _, ty::Dyn)) => {
(ty::Dynamic(data_a, _), ty::Dynamic(data_b, _)) => {
let val = self.read_immediate(src)?;
// MIR building generates odd NOP casts, prevent them from causing unexpected trouble.
// See <https://github.com/rust-lang/rust/issues/128880>.
@ -436,7 +436,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let new_vptr = self.get_vtable_ptr(ty, data_b)?;
self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest)
}
(_, &ty::Dynamic(data, _, ty::Dyn)) => {
(_, &ty::Dynamic(data, _)) => {
// Initial cast from sized to dyn trait
let vtable = self.get_vtable_ptr(src_pointee_ty, data)?;
let ptr = self.read_pointer(src)?;

View file

@ -4,6 +4,7 @@ use either::{Left, Right};
use rustc_abi::{Align, HasDataLayout, Size, TargetDataLayout};
use rustc_errors::DiagCtxtHandle;
use rustc_hir::def_id::DefId;
use rustc_hir::limit::Limit;
use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo};
use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::layout::{
@ -12,7 +13,6 @@ use rustc_middle::ty::layout::{
};
use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypingEnv, Variance};
use rustc_middle::{mir, span_bug};
use rustc_session::Limit;
use rustc_span::Span;
use rustc_target::callconv::FnAbi;
use tracing::{debug, trace};
@ -469,7 +469,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
interp_ok(Some((full_size, full_align)))
}
ty::Dynamic(expected_trait, _, ty::Dyn) => {
ty::Dynamic(expected_trait, _) => {
let vtable = metadata.unwrap_meta().to_pointer(self)?;
// Read size and align from vtable (already checks size).
interp_ok(Some(self.get_vtable_size_and_align(vtable, Some(expected_trait))?))

Some files were not shown because too many files have changed in this diff Show more