mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Merge ref 'e4fdb554ad2c' from rust-lang/rust
Pull recent changes from https://github.com/rust-lang/rust via Josh. Upstream ref: rust-lang/rust@e4fdb554ad Filtered ref: rust-lang/stdarch@ae05da8bd6 Upstream diff: https://github.com/rust-lang/rust/compare/eda4fc7733ee89e484d7120cafbd80dcb2fce66e...e4fdb554ad2c0270473181438e338c42b5b30b0c This merge was created using https://github.com/rust-lang/josh-sync.
This commit is contained in:
@@ -12,6 +12,9 @@ trim_trailing_whitespace = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[*.css]
|
||||
indent_style = tab
|
||||
|
||||
# some tests need trailing whitespace in output snapshots
|
||||
[tests/**]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
@@ -262,6 +262,7 @@ Guillaume Gomez <guillaume1.gomez@gmail.com>
|
||||
Guillaume Gomez <guillaume1.gomez@gmail.com> ggomez <ggomez@ggo.ifr.lan>
|
||||
Guillaume Gomez <guillaume1.gomez@gmail.com> Guillaume Gomez <ggomez@ggo.ifr.lan>
|
||||
Guillaume Gomez <guillaume1.gomez@gmail.com> Guillaume Gomez <guillaume.gomez@huawei.com>
|
||||
Guillaume Gomez <guillaume1.gomez@gmail.com> Guillaume Gomez <contact@guillaume-gomez.fr>
|
||||
gnzlbg <gonzalobg88@gmail.com> <gnzlbg@users.noreply.github.com>
|
||||
hamidreza kalbasi <hamidrezakalbasi@protonmail.com>
|
||||
Hanna Kruppe <hanna.kruppe@gmail.com> <robin.kruppe@gmail.com>
|
||||
|
||||
+184
-32
@@ -376,12 +376,41 @@ version = "3.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
|
||||
|
||||
[[package]]
|
||||
name = "bytecheck"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0caa33a2c0edca0419d15ac723dff03f1956f7978329b1e3b5fdaaaed9d3ca8b"
|
||||
dependencies = [
|
||||
"bytecheck_derive",
|
||||
"ptr_meta",
|
||||
"rancor",
|
||||
"simdutf8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytecheck_derive"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89385e82b5d1821d2219e0b095efa2cc1f246cbf99080f3be46a1a85c0d392d9"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytecount"
|
||||
version = "0.6.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
|
||||
|
||||
[[package]]
|
||||
name = "camino"
|
||||
version = "1.2.1"
|
||||
@@ -1111,9 +1140,9 @@ version = "0.1.96"
|
||||
|
||||
[[package]]
|
||||
name = "derive-where"
|
||||
version = "1.6.0"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f"
|
||||
checksum = "d08b3a0bcc0d079199cd476b2cae8435016ec11d1c0986c6901c5ac223041534"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2146,9 +2175,9 @@ checksum = "9fa0e2a1fcbe2f6be6c42e342259976206b383122fc152e872795338b5a3f3a7"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.177"
|
||||
version = "0.2.183"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
|
||||
checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
|
||||
|
||||
[[package]]
|
||||
name = "libdbus-sys"
|
||||
@@ -2425,11 +2454,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.1.0"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873"
|
||||
checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"wasi 0.11.1+wasi-snapshot-preview1",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
@@ -2461,6 +2491,7 @@ dependencies = [
|
||||
"libffi",
|
||||
"libloading 0.9.0",
|
||||
"measureme",
|
||||
"mio",
|
||||
"nix",
|
||||
"rand 0.9.2",
|
||||
"regex",
|
||||
@@ -2476,6 +2507,26 @@ dependencies = [
|
||||
name = "miropt-test-tools"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "munge"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e17401f259eba956ca16491461b6e8f72913a0a114e39736ce404410f915a0c"
|
||||
dependencies = [
|
||||
"munge_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "munge_macro"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "new_debug_unreachable"
|
||||
version = "1.0.6"
|
||||
@@ -2622,9 +2673,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objc2-core-foundation"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
|
||||
checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
@@ -2637,9 +2688,9 @@ checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33"
|
||||
|
||||
[[package]]
|
||||
name = "objc2-io-kit"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a"
|
||||
checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"objc2-core-foundation",
|
||||
@@ -3047,6 +3098,26 @@ dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ptr_meta"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b9a0cf95a1196af61d4f1cbdab967179516d9a4a4312af1f31948f8f6224a79"
|
||||
dependencies = [
|
||||
"ptr_meta_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ptr_meta_derive"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7347867d0a7e1208d93b46767be83e2b8f978c3dad35f775ac8d8847551d6fe1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pulldown-cmark"
|
||||
version = "0.11.3"
|
||||
@@ -3092,6 +3163,15 @@ version = "5.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||
|
||||
[[package]]
|
||||
name = "rancor"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a063ea72381527c2a0561da9c80000ef822bdd7c3241b1cc1b12100e3df081ee"
|
||||
dependencies = [
|
||||
"ptr_meta",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
@@ -3275,6 +3355,15 @@ dependencies = [
|
||||
name = "remote-test-server"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "rend"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6"
|
||||
dependencies = [
|
||||
"bytecheck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "replace-version-placeholder"
|
||||
version = "0.1.0"
|
||||
@@ -3283,6 +3372,36 @@ dependencies = [
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rkyv"
|
||||
version = "0.8.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a30e631b7f4a03dee9056b8ef6982e8ba371dd5bedb74d3ec86df4499132c70"
|
||||
dependencies = [
|
||||
"bytecheck",
|
||||
"bytes",
|
||||
"hashbrown 0.16.1",
|
||||
"indexmap",
|
||||
"munge",
|
||||
"ptr_meta",
|
||||
"rancor",
|
||||
"rend",
|
||||
"rkyv_derive",
|
||||
"tinyvec",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rkyv_derive"
|
||||
version = "0.8.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8100bb34c0a1d0f907143db3149e6b4eea3c33b9ee8b189720168e818303986f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.110",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "run_make_support"
|
||||
version = "0.0.0"
|
||||
@@ -3302,14 +3421,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustc-build-sysroot"
|
||||
version = "0.5.11"
|
||||
version = "0.5.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b881c015c729b43105bbd3702a9bdecee28fafaa21126d1d62e454ec011a4b7"
|
||||
checksum = "eec3905e8201688412f6f4b1f6c86d38b3ee6578f59ba85f41330a3af61e8365"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"rustc_version",
|
||||
"tempfile",
|
||||
"toml 0.8.23",
|
||||
"toml 1.1.0+spec-1.1.0",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
@@ -3902,7 +4021,6 @@ dependencies = [
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_infer",
|
||||
"rustc_lint",
|
||||
"rustc_lint_defs",
|
||||
"rustc_macros",
|
||||
"rustc_middle",
|
||||
@@ -4227,7 +4345,7 @@ dependencies = [
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_infer",
|
||||
"rustc_lint",
|
||||
"rustc_lint_defs",
|
||||
"rustc_macros",
|
||||
"rustc_middle",
|
||||
"rustc_pattern_analysis",
|
||||
@@ -4454,11 +4572,9 @@ dependencies = [
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
"rustc_middle",
|
||||
"rustc_serialize",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_thread_pool",
|
||||
"tracing",
|
||||
@@ -4790,6 +4906,7 @@ name = "rustdoc-json-types"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"rkyv",
|
||||
"rustc-hash 2.1.1",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
@@ -5078,9 +5195,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "1.0.3"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392"
|
||||
checksum = "876ac351060d4f882bb1032b6369eb0aef79ad9df1ea8bc404874d8cc3d0cd98"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
@@ -5128,6 +5245,12 @@ version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
||||
|
||||
[[package]]
|
||||
name = "simdutf8"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
|
||||
|
||||
[[package]]
|
||||
name = "similar"
|
||||
version = "2.7.0"
|
||||
@@ -5248,9 +5371,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "stringdex"
|
||||
version = "0.0.5"
|
||||
version = "0.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07ab85c3f308f022ce6861ab57576b5b6ebc4835f9577e67e0f35f6c351e3f0a"
|
||||
checksum = "155cb460a7ede06f71ac9961e28d3ba4b3408355e233f8edd158b957ceba3950"
|
||||
dependencies = [
|
||||
"stacker",
|
||||
]
|
||||
@@ -5315,9 +5438,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.38.2"
|
||||
version = "0.38.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1efc19935b4b66baa6f654ac7924c192f55b175c00a7ab72410fc24284dacda8"
|
||||
checksum = "92ab6a2f8bfe508deb3c6406578252e491d299cbbf3bc0529ecc3313aee4a52f"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"objc2-core-foundation",
|
||||
@@ -5337,9 +5460,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tar"
|
||||
version = "0.4.44"
|
||||
version = "0.4.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a"
|
||||
checksum = "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973"
|
||||
dependencies = [
|
||||
"filetime",
|
||||
"libc",
|
||||
@@ -5570,7 +5693,6 @@ version = "0.8.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned 0.6.9",
|
||||
"toml_datetime 0.6.11",
|
||||
@@ -5585,13 +5707,28 @@ checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde_core",
|
||||
"serde_spanned 1.0.3",
|
||||
"serde_spanned 1.1.0",
|
||||
"toml_datetime 0.7.3",
|
||||
"toml_parser",
|
||||
"toml_writer",
|
||||
"winnow 0.7.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "1.1.0+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8195ca05e4eb728f4ba94f3e3291661320af739c4e43779cbdfae82ab239fcc"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde_core",
|
||||
"serde_spanned 1.1.0",
|
||||
"toml_datetime 1.1.0+spec-1.1.0",
|
||||
"toml_parser",
|
||||
"toml_writer",
|
||||
"winnow 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.11"
|
||||
@@ -5610,6 +5747,15 @@ dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "1.1.0+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97251a7c317e03ad83774a8752a7e81fb6067740609f75ea2b585b569a59198f"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.19.15"
|
||||
@@ -5639,11 +5785,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml_parser"
|
||||
version = "1.0.4"
|
||||
version = "1.1.0+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e"
|
||||
checksum = "2334f11ee363607eb04df9b8fc8a13ca1715a72ba8662a26ac285c98aabb4011"
|
||||
dependencies = [
|
||||
"winnow 0.7.13",
|
||||
"winnow 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5654,9 +5800,9 @@ checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
|
||||
|
||||
[[package]]
|
||||
name = "toml_writer"
|
||||
version = "1.0.4"
|
||||
version = "1.1.0+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2"
|
||||
checksum = "d282ade6016312faf3e41e57ebbba0c073e4056dab1232ab1cb624199648f8ed"
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
@@ -6642,6 +6788,12 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8"
|
||||
|
||||
[[package]]
|
||||
name = "winsplit"
|
||||
version = "0.1.0"
|
||||
|
||||
+14
@@ -1,3 +1,17 @@
|
||||
Version 1.94.1 (2026-03-26)
|
||||
===========================
|
||||
|
||||
<a id="1.94.1"></a>
|
||||
|
||||
* [Fix `std::thread::spawn` on wasm32-wasip1-threads](https://github.com/rust-lang/rust/pull/153634)
|
||||
* [Remove new methods added to `std::os::windows::fs::OpenOptionsExt`](https://github.com/rust-lang/rust/pull/153491)
|
||||
The new methods were unstable, but the trait itself is not sealed and so
|
||||
cannot be extended with non-default methods.
|
||||
* [Clippy: fix ICE in `match_same_arms`](https://github.com/rust-lang/rust-clippy/pull/16685)
|
||||
* [Cargo: update tar to 0.4.45](https://github.com/rust-lang/cargo/pull/16769)
|
||||
This resolves CVE-2026-33055 and CVE-2026-33056. Users of crates.io are not affected.
|
||||
See [blog](https://blog.rust-lang.org/2026/03/21/cve-2026-33056/) for more details.
|
||||
|
||||
Version 1.94.0 (2026-03-05)
|
||||
==========================
|
||||
|
||||
|
||||
@@ -826,7 +826,8 @@
|
||||
# in the sysroot. It is required for running nvptx tests.
|
||||
#rust.llvm-bitcode-linker = false
|
||||
|
||||
# Whether to deny warnings in crates
|
||||
# Whether to deny warnings in crates. Set to `false` to avoid
|
||||
# error: warnings are denied by `build.warnings` configuration
|
||||
#rust.deny-warnings = true
|
||||
|
||||
# Print backtrace on internal compiler errors during bootstrap
|
||||
@@ -1013,9 +1014,10 @@
|
||||
# its historical default, but when compiling the compiler itself, we skip it by
|
||||
# default since we know it's safe to do so in that case.
|
||||
#
|
||||
# On Windows platforms, packed debuginfo is the only supported option,
|
||||
# producing a `.pdb` file.
|
||||
#split-debuginfo = if linux { off } else if windows { packed } else if apple { unpacked }
|
||||
# On Windows MSVC platforms, packed debuginfo is the only supported option,
|
||||
# producing a `.pdb` file. On Windows GNU rustc doesn't support splitting debuginfo,
|
||||
# and enabling it causes issues.
|
||||
#split-debuginfo = if linux || windows-gnu { off } else if windows-msvc { packed } else if apple { unpacked }
|
||||
|
||||
# Path to the `llvm-config` binary of the installation of a custom LLVM to link
|
||||
# against. Note that if this is specified we don't compile LLVM at all for this
|
||||
|
||||
@@ -83,7 +83,7 @@ pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, H
|
||||
}))
|
||||
}
|
||||
|
||||
BackendRepr::ScalableVector { .. } => {
|
||||
BackendRepr::SimdScalableVector { .. } => {
|
||||
unreachable!("`homogeneous_aggregate` should not be called for scalable vectors")
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
/// `b` is `FieldIdx(1)` in `VariantIdx(0)`,
|
||||
/// `d` is `FieldIdx(1)` in `VariantIdx(1)`, and
|
||||
/// `f` is `FieldIdx(1)` in `VariantIdx(0)`.
|
||||
#[cfg_attr(feature = "nightly", derive(rustc_macros::HashStable_Generic))]
|
||||
#[stable_hash_generic]
|
||||
#[encodable]
|
||||
#[orderable]
|
||||
#[gate_rustc_only]
|
||||
@@ -70,7 +70,7 @@ impl FieldIdx {
|
||||
///
|
||||
/// `struct`s, `tuples`, and `unions`s are considered to have a single variant
|
||||
/// with variant index zero, aka [`FIRST_VARIANT`].
|
||||
#[cfg_attr(feature = "nightly", derive(rustc_macros::HashStable_Generic))]
|
||||
#[stable_hash_generic]
|
||||
#[encodable]
|
||||
#[orderable]
|
||||
#[gate_rustc_only]
|
||||
@@ -210,7 +210,7 @@ pub fn scalable_vector_type<FieldIdx, VariantIdx, F>(
|
||||
VariantIdx: Idx,
|
||||
F: AsRef<LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
|
||||
{
|
||||
vector_type_layout(VectorKind::Scalable, self.cx.data_layout(), element, count)
|
||||
vector_type_layout(SimdVectorKind::Scalable, self.cx.data_layout(), element, count)
|
||||
}
|
||||
|
||||
pub fn simd_type<FieldIdx, VariantIdx, F>(
|
||||
@@ -224,7 +224,7 @@ pub fn simd_type<FieldIdx, VariantIdx, F>(
|
||||
VariantIdx: Idx,
|
||||
F: AsRef<LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
|
||||
{
|
||||
let kind = if repr_packed { VectorKind::PackedFixed } else { VectorKind::Fixed };
|
||||
let kind = if repr_packed { SimdVectorKind::PackedFixed } else { SimdVectorKind::Fixed };
|
||||
vector_type_layout(kind, self.cx.data_layout(), element, count)
|
||||
}
|
||||
|
||||
@@ -484,7 +484,7 @@ pub fn layout_of_union<
|
||||
BackendRepr::Scalar(..)
|
||||
| BackendRepr::ScalarPair(..)
|
||||
| BackendRepr::SimdVector { .. }
|
||||
| BackendRepr::ScalableVector { .. }
|
||||
| BackendRepr::SimdScalableVector { .. }
|
||||
| BackendRepr::Memory { .. } => repr,
|
||||
},
|
||||
};
|
||||
@@ -557,7 +557,7 @@ fn layout_of_struct<
|
||||
hide_niches(b);
|
||||
}
|
||||
BackendRepr::SimdVector { element, .. }
|
||||
| BackendRepr::ScalableVector { element, .. } => hide_niches(element),
|
||||
| BackendRepr::SimdScalableVector { element, .. } => hide_niches(element),
|
||||
BackendRepr::Memory { sized: _ } => {}
|
||||
}
|
||||
st.largest_niche = None;
|
||||
@@ -1524,7 +1524,7 @@ fn format_field_niches<
|
||||
}
|
||||
}
|
||||
|
||||
enum VectorKind {
|
||||
enum SimdVectorKind {
|
||||
/// `#[rustc_scalable_vector]`
|
||||
Scalable,
|
||||
/// `#[repr(simd, packed)]`
|
||||
@@ -1534,7 +1534,7 @@ enum VectorKind {
|
||||
}
|
||||
|
||||
fn vector_type_layout<FieldIdx, VariantIdx, F>(
|
||||
kind: VectorKind,
|
||||
kind: SimdVectorKind,
|
||||
dl: &TargetDataLayout,
|
||||
element: F,
|
||||
count: u64,
|
||||
@@ -1559,16 +1559,16 @@ fn vector_type_layout<FieldIdx, VariantIdx, F>(
|
||||
let size =
|
||||
elt.size.checked_mul(count, dl).ok_or_else(|| LayoutCalculatorError::SizeOverflow)?;
|
||||
let (repr, align) = match kind {
|
||||
VectorKind::Scalable => {
|
||||
(BackendRepr::ScalableVector { element, count }, dl.llvmlike_vector_align(size))
|
||||
SimdVectorKind::Scalable => {
|
||||
(BackendRepr::SimdScalableVector { element, count }, dl.llvmlike_vector_align(size))
|
||||
}
|
||||
// Non-power-of-two vectors have padding up to the next power-of-two.
|
||||
// If we're a packed repr, remove the padding while keeping the alignment as close
|
||||
// to a vector as possible.
|
||||
VectorKind::PackedFixed if !count.is_power_of_two() => {
|
||||
SimdVectorKind::PackedFixed if !count.is_power_of_two() => {
|
||||
(BackendRepr::Memory { sized: true }, Align::max_aligned_factor(size))
|
||||
}
|
||||
VectorKind::PackedFixed | VectorKind::Fixed => {
|
||||
SimdVectorKind::PackedFixed | SimdVectorKind::Fixed => {
|
||||
(BackendRepr::SimdVector { element, count }, dl.llvmlike_vector_align(size))
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1000,20 +1000,6 @@ pub enum AlignFromBytesError {
|
||||
TooLarge(u64),
|
||||
}
|
||||
|
||||
impl AlignFromBytesError {
|
||||
pub fn diag_ident(self) -> &'static str {
|
||||
match self {
|
||||
Self::NotPowerOfTwo(_) => "not_power_of_two",
|
||||
Self::TooLarge(_) => "too_large",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn align(self) -> u64 {
|
||||
let (Self::NotPowerOfTwo(align) | Self::TooLarge(align)) = self;
|
||||
align
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for AlignFromBytesError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Display::fmt(self, f)
|
||||
@@ -1023,8 +1009,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
impl fmt::Display for AlignFromBytesError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
AlignFromBytesError::NotPowerOfTwo(align) => write!(f, "`{align}` is not a power of 2"),
|
||||
AlignFromBytesError::TooLarge(align) => write!(f, "`{align}` is too large"),
|
||||
AlignFromBytesError::NotPowerOfTwo(align) => write!(f, "{align} is not a power of 2"),
|
||||
AlignFromBytesError::TooLarge(align) => write!(f, "{align} is too large"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1731,7 +1717,7 @@ impl AddressSpace {
|
||||
pub enum BackendRepr {
|
||||
Scalar(Scalar),
|
||||
ScalarPair(Scalar, Scalar),
|
||||
ScalableVector {
|
||||
SimdScalableVector {
|
||||
element: Scalar,
|
||||
count: u64,
|
||||
},
|
||||
@@ -1758,7 +1744,7 @@ pub fn is_unsized(&self) -> bool {
|
||||
// fully implemented, scalable vectors will remain `Sized`, they just won't be
|
||||
// `const Sized` - whether `is_unsized` continues to return `false` at that point will
|
||||
// need to be revisited and will depend on what `is_unsized` is used for.
|
||||
| BackendRepr::ScalableVector { .. }
|
||||
| BackendRepr::SimdScalableVector { .. }
|
||||
| BackendRepr::SimdVector { .. } => false,
|
||||
BackendRepr::Memory { sized } => !sized,
|
||||
}
|
||||
@@ -1801,7 +1787,7 @@ pub fn scalar_align<C: HasDataLayout>(&self, cx: &C) -> Option<Align> {
|
||||
// The align of a Vector can vary in surprising ways
|
||||
BackendRepr::SimdVector { .. }
|
||||
| BackendRepr::Memory { .. }
|
||||
| BackendRepr::ScalableVector { .. } => None,
|
||||
| BackendRepr::SimdScalableVector { .. } => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1825,7 +1811,7 @@ pub fn scalar_size<C: HasDataLayout>(&self, cx: &C) -> Option<Size> {
|
||||
// The size of a Vector can vary in surprising ways
|
||||
BackendRepr::SimdVector { .. }
|
||||
| BackendRepr::Memory { .. }
|
||||
| BackendRepr::ScalableVector { .. } => None,
|
||||
| BackendRepr::SimdScalableVector { .. } => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1840,8 +1826,8 @@ pub fn to_union(&self) -> Self {
|
||||
BackendRepr::SimdVector { element: element.to_union(), count }
|
||||
}
|
||||
BackendRepr::Memory { .. } => BackendRepr::Memory { sized: true },
|
||||
BackendRepr::ScalableVector { element, count } => {
|
||||
BackendRepr::ScalableVector { element: element.to_union(), count }
|
||||
BackendRepr::SimdScalableVector { element, count } => {
|
||||
BackendRepr::SimdScalableVector { element: element.to_union(), count }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2085,7 +2071,7 @@ pub fn is_aggregate(&self) -> bool {
|
||||
match self.backend_repr {
|
||||
BackendRepr::Scalar(_)
|
||||
| BackendRepr::SimdVector { .. }
|
||||
| BackendRepr::ScalableVector { .. } => false,
|
||||
| BackendRepr::SimdScalableVector { .. } => false,
|
||||
BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => true,
|
||||
}
|
||||
}
|
||||
@@ -2182,13 +2168,13 @@ pub fn is_1zst(&self) -> bool {
|
||||
|
||||
/// Returns `true` if the size of the type is only known at runtime.
|
||||
pub fn is_runtime_sized(&self) -> bool {
|
||||
matches!(self.backend_repr, BackendRepr::ScalableVector { .. })
|
||||
matches!(self.backend_repr, BackendRepr::SimdScalableVector { .. })
|
||||
}
|
||||
|
||||
/// Returns the elements count of a scalable vector.
|
||||
pub fn scalable_vector_element_count(&self) -> Option<u64> {
|
||||
match self.backend_repr {
|
||||
BackendRepr::ScalableVector { count, .. } => Some(count),
|
||||
BackendRepr::SimdScalableVector { count, .. } => Some(count),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -2201,7 +2187,7 @@ pub fn is_zst(&self) -> bool {
|
||||
match self.backend_repr {
|
||||
BackendRepr::Scalar(_)
|
||||
| BackendRepr::ScalarPair(..)
|
||||
| BackendRepr::ScalableVector { .. }
|
||||
| BackendRepr::SimdScalableVector { .. }
|
||||
| BackendRepr::SimdVector { .. } => false,
|
||||
BackendRepr::Memory { sized } => sized && self.size.bytes() == 0,
|
||||
}
|
||||
|
||||
@@ -30,8 +30,9 @@
|
||||
use rustc_data_structures::tagged_ptr::Tag;
|
||||
use rustc_macros::{Decodable, Encodable, HashStable_Generic, Walkable};
|
||||
pub use rustc_span::AttrId;
|
||||
use rustc_span::source_map::{Spanned, respan};
|
||||
use rustc_span::{ByteSymbol, DUMMY_SP, ErrorGuaranteed, Ident, Span, Symbol, kw, sym};
|
||||
use rustc_span::{
|
||||
ByteSymbol, DUMMY_SP, ErrorGuaranteed, Ident, Span, Spanned, Symbol, kw, respan, sym,
|
||||
};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
|
||||
use crate::attr::data_structures::CfgEntry;
|
||||
@@ -937,7 +938,7 @@ pub enum PatKind {
|
||||
Never,
|
||||
|
||||
/// A guard pattern (e.g., `x if guard(x)`).
|
||||
Guard(Box<Pat>, Box<Expr>),
|
||||
Guard(Box<Pat>, Box<Guard>),
|
||||
|
||||
/// Parentheses in patterns used for grouping (i.e., `(PAT)`).
|
||||
Paren(Box<Pat>),
|
||||
@@ -1345,7 +1346,7 @@ pub struct Arm {
|
||||
/// Match arm pattern, e.g. `10` in `match foo { 10 => {}, _ => {} }`.
|
||||
pub pat: Box<Pat>,
|
||||
/// Match arm guard, e.g. `n > 10` in `match foo { n if n > 10 => {}, _ => {} }`.
|
||||
pub guard: Option<Box<Expr>>,
|
||||
pub guard: Option<Box<Guard>>,
|
||||
/// Match arm body. Omitted if the pattern is a never pattern.
|
||||
pub body: Option<Box<Expr>>,
|
||||
pub span: Span,
|
||||
@@ -3953,6 +3954,18 @@ impl ConstBlockItem {
|
||||
pub const IDENT: Ident = Ident { name: kw::Underscore, span: DUMMY_SP };
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
||||
pub struct Guard {
|
||||
pub cond: Expr,
|
||||
pub span_with_leading_if: Span,
|
||||
}
|
||||
|
||||
impl Guard {
|
||||
pub fn span(&self) -> Span {
|
||||
self.cond.span
|
||||
}
|
||||
}
|
||||
|
||||
// Adding a new variant? Please update `test_item` in `tests/ui/macros/stringify.rs`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum ItemKind {
|
||||
|
||||
@@ -876,11 +876,15 @@ pub trait AttributeExt: Debug {
|
||||
/// a doc comment) will return `false`.
|
||||
fn is_doc_comment(&self) -> Option<Span>;
|
||||
|
||||
/// Returns true if the attribute's first *and only* path segment is equal to the passed-in
|
||||
/// symbol.
|
||||
#[inline]
|
||||
fn has_name(&self, name: Symbol) -> bool {
|
||||
self.name().map(|x| x == name).unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Returns true if the attribute's first *and only* path segment is any of the passed-in
|
||||
/// symbols.
|
||||
#[inline]
|
||||
fn has_any_name(&self, names: &[Symbol]) -> bool {
|
||||
names.iter().any(|&name| self.has_name(name))
|
||||
@@ -889,6 +893,7 @@ fn has_any_name(&self, names: &[Symbol]) -> bool {
|
||||
/// get the span of the entire attribute
|
||||
fn span(&self) -> Span;
|
||||
|
||||
/// Returns whether the attribute is a path, without any arguments.
|
||||
fn is_word(&self) -> bool;
|
||||
|
||||
fn path(&self) -> SmallVec<[Symbol; 1]> {
|
||||
@@ -911,11 +916,14 @@ fn has_any_name(&self, names: &[Symbol]) -> bool {
|
||||
/// * `#[deprecated(note = "note", ...)]` returns `Some("note")`.
|
||||
fn deprecation_note(&self) -> Option<Ident>;
|
||||
|
||||
/// Returns whether this attribute is any of the proc macro attributes.
|
||||
/// i.e. `proc_macro`, `proc_macro_attribute` or `proc_macro_derive`.
|
||||
fn is_proc_macro_attr(&self) -> bool {
|
||||
[sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
|
||||
.iter()
|
||||
.any(|kind| self.has_name(*kind))
|
||||
}
|
||||
/// Returns true if this attribute is `#[automatically_deived]`.
|
||||
fn is_automatically_derived_attr(&self) -> bool;
|
||||
|
||||
/// Returns the documentation and its kind if this is a doc comment or a sugared doc comment.
|
||||
|
||||
@@ -11,8 +11,7 @@
|
||||
use std::panic;
|
||||
|
||||
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::{Ident, Span, Symbol};
|
||||
use rustc_span::{Ident, Span, Spanned, Symbol};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
|
||||
@@ -94,6 +94,7 @@ pub enum MetaVarKind {
|
||||
},
|
||||
Path,
|
||||
Vis,
|
||||
Guard,
|
||||
TT,
|
||||
}
|
||||
|
||||
@@ -114,6 +115,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
MetaVarKind::Meta { .. } => sym::meta,
|
||||
MetaVarKind::Path => sym::path,
|
||||
MetaVarKind::Vis => sym::vis,
|
||||
MetaVarKind::Guard => sym::guard,
|
||||
MetaVarKind::TT => sym::tt,
|
||||
};
|
||||
write!(f, "{sym}")
|
||||
@@ -1124,6 +1126,7 @@ pub enum NonterminalKind {
|
||||
Meta,
|
||||
Path,
|
||||
Vis,
|
||||
Guard,
|
||||
TT,
|
||||
}
|
||||
|
||||
@@ -1161,6 +1164,7 @@ pub fn from_symbol(
|
||||
sym::meta => NonterminalKind::Meta,
|
||||
sym::path => NonterminalKind::Path,
|
||||
sym::vis => NonterminalKind::Vis,
|
||||
sym::guard => NonterminalKind::Guard,
|
||||
sym::tt => NonterminalKind::TT,
|
||||
_ => return None,
|
||||
})
|
||||
@@ -1182,6 +1186,7 @@ fn symbol(self) -> Symbol {
|
||||
NonterminalKind::Meta => sym::meta,
|
||||
NonterminalKind::Path => sym::path,
|
||||
NonterminalKind::Vis => sym::vis,
|
||||
NonterminalKind::Guard => sym::guard,
|
||||
NonterminalKind::TT => sym::tt,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,7 @@
|
||||
|
||||
pub use rustc_ast_ir::visit::VisitorResult;
|
||||
pub use rustc_ast_ir::{try_visit, visit_opt, walk_list, walk_visitable_list};
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::{Ident, Span, Symbol};
|
||||
use rustc_span::{Ident, Span, Spanned, Symbol};
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
use crate::ast::*;
|
||||
@@ -443,6 +442,7 @@ pub fn ctxt(&self) -> Option<FnCtxt> {
|
||||
FormatArguments,
|
||||
FormatPlaceholder,
|
||||
GenericParamKind,
|
||||
Guard,
|
||||
Impl,
|
||||
ImplPolarity,
|
||||
Inline,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::fmt::Write;
|
||||
|
||||
use rustc_ast::*;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
||||
@@ -23,7 +22,7 @@
|
||||
AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, ParamMode, ResolverAstLoweringExt,
|
||||
};
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
pub(crate) fn lower_inline_asm(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
@@ -124,13 +123,9 @@ pub(crate) fn lower_inline_asm(
|
||||
self.dcx().emit_err(ClobberAbiNotSupported { abi_span: *abi_span });
|
||||
}
|
||||
Err(supported_abis) => {
|
||||
let mut abis = format!("`{}`", supported_abis[0]);
|
||||
for m in &supported_abis[1..] {
|
||||
let _ = write!(abis, ", `{m}`");
|
||||
}
|
||||
self.dcx().emit_err(InvalidAbiClobberAbi {
|
||||
abi_span: *abi_span,
|
||||
supported_abis: abis,
|
||||
supported_abis: supported_abis.to_vec().into(),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -164,15 +159,12 @@ pub(crate) fn lower_inline_asm(
|
||||
asm::InlineAsmRegOrRegClass::RegClass(if let Some(asm_arch) = asm_arch {
|
||||
asm::InlineAsmRegClass::parse(asm_arch, reg_class).unwrap_or_else(
|
||||
|supported_register_classes| {
|
||||
let mut register_classes =
|
||||
format!("`{}`", supported_register_classes[0]);
|
||||
for m in &supported_register_classes[1..] {
|
||||
let _ = write!(register_classes, ", `{m}`");
|
||||
}
|
||||
self.dcx().emit_err(InvalidRegisterClass {
|
||||
op_span: *op_sp,
|
||||
reg_class,
|
||||
supported_register_classes: register_classes,
|
||||
supported_register_classes: supported_register_classes
|
||||
.to_vec()
|
||||
.into(),
|
||||
});
|
||||
asm::InlineAsmRegClass::Err
|
||||
},
|
||||
@@ -272,23 +264,20 @@ pub(crate) fn lower_inline_asm(
|
||||
}
|
||||
let valid_modifiers = class.valid_modifiers(asm_arch.unwrap());
|
||||
if !valid_modifiers.contains(&modifier) {
|
||||
let sub = if !valid_modifiers.is_empty() {
|
||||
let mut mods = format!("`{}`", valid_modifiers[0]);
|
||||
for m in &valid_modifiers[1..] {
|
||||
let _ = write!(mods, ", `{m}`");
|
||||
}
|
||||
InvalidAsmTemplateModifierRegClassSub::SupportModifier {
|
||||
class_name: class.name(),
|
||||
modifiers: mods,
|
||||
}
|
||||
} else {
|
||||
let sub = if valid_modifiers.is_empty() {
|
||||
InvalidAsmTemplateModifierRegClassSub::DoesNotSupportModifier {
|
||||
class_name: class.name(),
|
||||
}
|
||||
} else {
|
||||
InvalidAsmTemplateModifierRegClassSub::SupportModifier {
|
||||
class_name: class.name(),
|
||||
modifiers: valid_modifiers.to_vec().into(),
|
||||
}
|
||||
};
|
||||
self.dcx().emit_err(InvalidAsmTemplateModifierRegClass {
|
||||
placeholder_span,
|
||||
op_span: op_sp,
|
||||
modifier: modifier.to_string(),
|
||||
sub,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
use rustc_span::sym;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext};
|
||||
use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext, ResolverAstLoweringExt};
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
pub(super) fn lower_block(
|
||||
&mut self,
|
||||
b: &Block,
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
use thin_vec::thin_vec;
|
||||
|
||||
use crate::LoweringContext;
|
||||
use crate::{LoweringContext, ResolverAstLoweringExt};
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
/// Lowered contracts are guarded with the `contract_checks` compiler flag,
|
||||
/// i.e. the flag turns into a boolean guard in the lowered HIR. The reason
|
||||
/// for not eliminating the contract code entirely when the `contract_checks`
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
//! also be emitted during HIR ty lowering.
|
||||
|
||||
use std::iter;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use ast::visit::Visitor;
|
||||
use hir::def::{DefKind, PartialRes, Res};
|
||||
@@ -44,16 +45,15 @@
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::*;
|
||||
use rustc_attr_parsing::{AttributeParser, ShouldEmit};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::attrs::{AttributeKind, InlineAttr};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{Asyncness, DelegationAttrs, DelegationFnSigAttrs, ResolverAstLowering};
|
||||
use rustc_middle::ty::Asyncness;
|
||||
use rustc_span::symbol::kw;
|
||||
use rustc_span::{DUMMY_SP, Ident, Span, Symbol};
|
||||
use rustc_span::{Ident, Span, Symbol};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::delegation::generics::{GenericsGenerationResult, GenericsGenerationResults};
|
||||
@@ -79,7 +79,7 @@ struct AttrAdditionInfo {
|
||||
|
||||
enum AttrAdditionKind {
|
||||
Default { factory: fn(Span) -> hir::Attribute },
|
||||
Inherit { flag: DelegationFnSigAttrs, factory: fn(Span, &hir::Attribute) -> hir::Attribute },
|
||||
Inherit { factory: fn(Span, &hir::Attribute) -> hir::Attribute },
|
||||
}
|
||||
|
||||
const PARENT_ID: hir::ItemLocalId = hir::ItemLocalId::ZERO;
|
||||
@@ -96,7 +96,6 @@ enum AttrAdditionKind {
|
||||
|
||||
hir::Attribute::Parsed(AttributeKind::MustUse { span, reason })
|
||||
},
|
||||
flag: DelegationFnSigAttrs::MUST_USE,
|
||||
},
|
||||
},
|
||||
AttrAdditionInfo {
|
||||
@@ -107,45 +106,11 @@ enum AttrAdditionKind {
|
||||
},
|
||||
];
|
||||
|
||||
type DelegationIdsVec = SmallVec<[DefId; 1]>;
|
||||
|
||||
// As delegations can now refer to another delegation, we have a delegation path
|
||||
// of the following type: reuse (current delegation) <- reuse (delegee_id) <- ... <- reuse <- function (root_function_id).
|
||||
// In its most basic and widely used form: reuse (current delegation) <- function (delegee_id, root_function_id)
|
||||
struct DelegationIds {
|
||||
path: DelegationIdsVec,
|
||||
}
|
||||
|
||||
impl DelegationIds {
|
||||
fn new(path: DelegationIdsVec) -> Self {
|
||||
assert!(!path.is_empty());
|
||||
Self { path }
|
||||
}
|
||||
|
||||
// Id of the first function in (non)local crate that is being reused
|
||||
fn root_function_id(&self) -> DefId {
|
||||
*self.path.last().expect("Ids vector can't be empty")
|
||||
}
|
||||
|
||||
// Id of the first definition which is being reused,
|
||||
// can be either function, in this case `root_id == delegee_id`, or other delegation
|
||||
fn delegee_id(&self) -> DefId {
|
||||
*self.path.first().expect("Ids vector can't be empty")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
fn is_method(&self, def_id: DefId, span: Span) -> bool {
|
||||
match self.tcx.def_kind(def_id) {
|
||||
DefKind::Fn => false,
|
||||
DefKind::AssocFn => match def_id.as_local() {
|
||||
Some(local_def_id) => self
|
||||
.resolver
|
||||
.delegation_fn_sigs
|
||||
.get(&local_def_id)
|
||||
.is_some_and(|sig| sig.has_self),
|
||||
None => self.tcx.associated_item(def_id).is_method(),
|
||||
},
|
||||
DefKind::AssocFn => self.tcx.associated_item(def_id).is_method(),
|
||||
_ => span_bug!(span, "unexpected DefKind for delegation item"),
|
||||
}
|
||||
}
|
||||
@@ -158,10 +123,10 @@ pub(crate) fn lower_delegation(
|
||||
let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span);
|
||||
|
||||
// Delegation can be unresolved in illegal places such as function bodies in extern blocks (see #151356)
|
||||
let ids = if let Some(delegation_info) =
|
||||
self.resolver.delegation_infos.get(&self.local_def_id(item_id))
|
||||
let sig_id = if let Some(delegation_info) =
|
||||
self.resolver.delegation_info(self.local_def_id(item_id))
|
||||
{
|
||||
self.get_delegation_ids(delegation_info.resolution_node, span)
|
||||
self.get_sig_id(delegation_info.resolution_node, span)
|
||||
} else {
|
||||
return self.generate_delegation_error(
|
||||
self.dcx().span_delayed_bug(
|
||||
@@ -173,60 +138,34 @@ pub(crate) fn lower_delegation(
|
||||
);
|
||||
};
|
||||
|
||||
match ids {
|
||||
Ok(ids) => {
|
||||
self.add_attrs_if_needed(span, &ids);
|
||||
match sig_id {
|
||||
Ok(sig_id) => {
|
||||
self.add_attrs_if_needed(span, sig_id);
|
||||
|
||||
let delegee_id = ids.delegee_id();
|
||||
let root_function_id = ids.root_function_id();
|
||||
let is_method = self.is_method(sig_id, span);
|
||||
|
||||
// `is_method` is used to choose the name of the first parameter (`self` or `arg0`),
|
||||
// if the original function is not a method (without `self`), then it can not be added
|
||||
// during chain of reuses, so we use `root_function_id` here
|
||||
let is_method = self.is_method(root_function_id, span);
|
||||
let (param_count, c_variadic) = self.param_count(sig_id);
|
||||
|
||||
// Here we use `root_function_id` as we can not get params information out of potential delegation reuse,
|
||||
// we need a function to extract this information
|
||||
let (param_count, c_variadic) = self.param_count(root_function_id);
|
||||
|
||||
let mut generics = self.lower_delegation_generics(
|
||||
delegation,
|
||||
ids.root_function_id(),
|
||||
item_id,
|
||||
span,
|
||||
);
|
||||
let mut generics = self.uplift_delegation_generics(delegation, sig_id, item_id);
|
||||
|
||||
let body_id = self.lower_delegation_body(
|
||||
delegation,
|
||||
item_id,
|
||||
is_method,
|
||||
param_count,
|
||||
&mut generics,
|
||||
span,
|
||||
);
|
||||
|
||||
// Here we use `delegee_id`, as this id will then be used to calculate parent for generics
|
||||
// inheritance, and we want this id to point on a delegee, not on the original
|
||||
// function (see https://github.com/rust-lang/rust/issues/150152#issuecomment-3674834654)
|
||||
let decl = self.lower_delegation_decl(
|
||||
delegee_id,
|
||||
param_count,
|
||||
c_variadic,
|
||||
span,
|
||||
&generics,
|
||||
);
|
||||
let decl =
|
||||
self.lower_delegation_decl(sig_id, param_count, c_variadic, span, &generics);
|
||||
|
||||
// Here we pass `root_function_id` as we want to inherit signature (including consts, async)
|
||||
// from the root function that started delegation
|
||||
let sig = self.lower_delegation_sig(root_function_id, decl, span);
|
||||
let sig = self.lower_delegation_sig(sig_id, decl, span);
|
||||
let ident = self.lower_ident(delegation.ident);
|
||||
|
||||
let generics = self.arena.alloc(hir::Generics {
|
||||
has_where_clause_predicates: false,
|
||||
params: self.arena.alloc_from_iter(generics.all_params(item_id, span, self)),
|
||||
predicates: self
|
||||
.arena
|
||||
.alloc_from_iter(generics.all_predicates(item_id, span, self)),
|
||||
params: self.arena.alloc_from_iter(generics.all_params(span, self)),
|
||||
predicates: self.arena.alloc_from_iter(generics.all_predicates(span, self)),
|
||||
span,
|
||||
where_clause_span: span,
|
||||
});
|
||||
@@ -237,9 +176,9 @@ pub(crate) fn lower_delegation(
|
||||
}
|
||||
}
|
||||
|
||||
fn add_attrs_if_needed(&mut self, span: Span, ids: &DelegationIds) {
|
||||
fn add_attrs_if_needed(&mut self, span: Span, sig_id: DefId) {
|
||||
let new_attrs =
|
||||
self.create_new_attrs(ATTRS_ADDITIONS, span, ids, self.attrs.get(&PARENT_ID));
|
||||
self.create_new_attrs(ATTRS_ADDITIONS, span, sig_id, self.attrs.get(&PARENT_ID));
|
||||
|
||||
if new_attrs.is_empty() {
|
||||
return;
|
||||
@@ -259,15 +198,9 @@ fn create_new_attrs(
|
||||
&self,
|
||||
candidate_additions: &[AttrAdditionInfo],
|
||||
span: Span,
|
||||
ids: &DelegationIds,
|
||||
sig_id: DefId,
|
||||
existing_attrs: Option<&&[hir::Attribute]>,
|
||||
) -> Vec<hir::Attribute> {
|
||||
let defs_orig_attrs = ids
|
||||
.path
|
||||
.iter()
|
||||
.map(|def_id| (*def_id, self.parse_local_original_attrs(*def_id)))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
candidate_additions
|
||||
.iter()
|
||||
.filter_map(|addition_info| {
|
||||
@@ -281,83 +214,22 @@ fn create_new_attrs(
|
||||
|
||||
match addition_info.kind {
|
||||
AttrAdditionKind::Default { factory } => Some(factory(span)),
|
||||
AttrAdditionKind::Inherit { flag, factory } => {
|
||||
for (def_id, orig_attrs) in &defs_orig_attrs {
|
||||
let original_attr = match def_id.as_local() {
|
||||
Some(local_id) => self
|
||||
.get_attrs(local_id)
|
||||
.flags
|
||||
.contains(flag)
|
||||
.then(|| {
|
||||
orig_attrs
|
||||
.as_ref()
|
||||
.map(|attrs| {
|
||||
attrs.iter().find(|base_attr| {
|
||||
(addition_info.equals)(base_attr)
|
||||
})
|
||||
})
|
||||
.flatten()
|
||||
})
|
||||
.flatten(),
|
||||
None =>
|
||||
{
|
||||
#[allow(deprecated)]
|
||||
self.tcx
|
||||
.get_all_attrs(*def_id)
|
||||
.iter()
|
||||
.find(|base_attr| (addition_info.equals)(base_attr))
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(original_attr) = original_attr {
|
||||
return Some(factory(span, original_attr));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
AttrAdditionKind::Inherit { factory, .. } =>
|
||||
{
|
||||
#[allow(deprecated)]
|
||||
self.tcx
|
||||
.get_all_attrs(sig_id)
|
||||
.iter()
|
||||
.find_map(|a| (addition_info.equals)(a).then(|| factory(span, a)))
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn parse_local_original_attrs(&self, def_id: DefId) -> Option<Vec<hir::Attribute>> {
|
||||
if let Some(local_id) = def_id.as_local() {
|
||||
let attrs = &self.get_attrs(local_id).to_inherit;
|
||||
|
||||
if !attrs.is_empty() {
|
||||
return Some(AttributeParser::parse_limited_all(
|
||||
self.tcx.sess,
|
||||
attrs,
|
||||
None,
|
||||
hir::Target::Fn,
|
||||
DUMMY_SP,
|
||||
DUMMY_NODE_ID,
|
||||
Some(self.tcx.features()),
|
||||
ShouldEmit::Nothing,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn get_attrs(&self, local_id: LocalDefId) -> &DelegationAttrs {
|
||||
// local_id can correspond either to a function or other delegation
|
||||
if let Some(fn_sig) = self.resolver.delegation_fn_sigs.get(&local_id) {
|
||||
&fn_sig.attrs
|
||||
} else {
|
||||
&self.resolver.delegation_infos[&local_id].attrs
|
||||
}
|
||||
}
|
||||
|
||||
fn get_delegation_ids(
|
||||
&self,
|
||||
mut node_id: NodeId,
|
||||
span: Span,
|
||||
) -> Result<DelegationIds, ErrorGuaranteed> {
|
||||
fn get_sig_id(&self, mut node_id: NodeId, span: Span) -> Result<DefId, ErrorGuaranteed> {
|
||||
let mut visited: FxHashSet<NodeId> = Default::default();
|
||||
let mut path: DelegationIdsVec = Default::default();
|
||||
let mut path: SmallVec<[DefId; 1]> = Default::default();
|
||||
|
||||
loop {
|
||||
visited.insert(node_id);
|
||||
@@ -378,7 +250,7 @@ fn get_delegation_ids(
|
||||
// it means that we refer to another delegation as a callee, so in order to obtain
|
||||
// a signature DefId we obtain NodeId of the callee delegation and try to get signature from it.
|
||||
if let Some(local_id) = def_id.as_local()
|
||||
&& let Some(delegation_info) = self.resolver.delegation_infos.get(&local_id)
|
||||
&& let Some(delegation_info) = self.resolver.delegation_info(local_id)
|
||||
{
|
||||
node_id = delegation_info.resolution_node;
|
||||
if visited.contains(&node_id) {
|
||||
@@ -390,7 +262,7 @@ fn get_delegation_ids(
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return Ok(DelegationIds::new(path));
|
||||
return Ok(path[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -401,15 +273,8 @@ fn get_resolution_id(&self, node_id: NodeId) -> Option<DefId> {
|
||||
|
||||
// Function parameter count, including C variadic `...` if present.
|
||||
fn param_count(&self, def_id: DefId) -> (usize, bool /*c_variadic*/) {
|
||||
if let Some(local_sig_id) = def_id.as_local() {
|
||||
match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
|
||||
Some(sig) => (sig.param_count, sig.c_variadic),
|
||||
None => (0, false),
|
||||
}
|
||||
} else {
|
||||
let sig = self.tcx.fn_sig(def_id).skip_binder().skip_binder();
|
||||
(sig.inputs().len() + usize::from(sig.c_variadic), sig.c_variadic)
|
||||
}
|
||||
let sig = self.tcx.fn_sig(def_id).skip_binder().skip_binder();
|
||||
(sig.inputs().len() + usize::from(sig.c_variadic), sig.c_variadic)
|
||||
}
|
||||
|
||||
fn lower_delegation_decl(
|
||||
@@ -425,19 +290,22 @@ fn lower_delegation_decl(
|
||||
let decl_param_count = param_count - c_variadic as usize;
|
||||
let inputs = self.arena.alloc_from_iter((0..decl_param_count).map(|arg| hir::Ty {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::TyKind::InferDelegation(sig_id, hir::InferDelegationKind::Input(arg)),
|
||||
kind: hir::TyKind::InferDelegation(hir::InferDelegation::Sig(
|
||||
sig_id,
|
||||
hir::InferDelegationSig::Input(arg),
|
||||
)),
|
||||
span,
|
||||
}));
|
||||
|
||||
let output = self.arena.alloc(hir::Ty {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::TyKind::InferDelegation(
|
||||
kind: hir::TyKind::InferDelegation(hir::InferDelegation::Sig(
|
||||
sig_id,
|
||||
hir::InferDelegationKind::Output(self.arena.alloc(hir::DelegationGenerics {
|
||||
hir::InferDelegationSig::Output(self.arena.alloc(hir::DelegationGenerics {
|
||||
child_args_segment_id: generics.child.args_segment_id,
|
||||
parent_args_segment_id: generics.parent.args_segment_id,
|
||||
})),
|
||||
),
|
||||
)),
|
||||
span,
|
||||
});
|
||||
|
||||
@@ -456,41 +324,21 @@ fn lower_delegation_sig(
|
||||
decl: &'hir hir::FnDecl<'hir>,
|
||||
span: Span,
|
||||
) -> hir::FnSig<'hir> {
|
||||
let header = if let Some(local_sig_id) = sig_id.as_local() {
|
||||
match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
|
||||
Some(sig) => {
|
||||
let parent = self.tcx.parent(sig_id);
|
||||
// HACK: we override the default safety instead of generating attributes from the ether.
|
||||
// We are not forwarding the attributes, as the delegation fn sigs are collected on the ast,
|
||||
// and here we need the hir attributes.
|
||||
let default_safety =
|
||||
if sig.attrs.flags.contains(DelegationFnSigAttrs::TARGET_FEATURE)
|
||||
|| self.tcx.def_kind(parent) == DefKind::ForeignMod
|
||||
{
|
||||
hir::Safety::Unsafe
|
||||
} else {
|
||||
hir::Safety::Safe
|
||||
};
|
||||
self.lower_fn_header(sig.header, default_safety, &[])
|
||||
}
|
||||
None => self.generate_header_error(),
|
||||
}
|
||||
} else {
|
||||
let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder();
|
||||
let asyncness = match self.tcx.asyncness(sig_id) {
|
||||
Asyncness::Yes => hir::IsAsync::Async(span),
|
||||
Asyncness::No => hir::IsAsync::NotAsync,
|
||||
};
|
||||
hir::FnHeader {
|
||||
safety: if self.tcx.codegen_fn_attrs(sig_id).safe_target_features {
|
||||
hir::HeaderSafety::SafeTargetFeatures
|
||||
} else {
|
||||
hir::HeaderSafety::Normal(sig.safety)
|
||||
},
|
||||
constness: self.tcx.constness(sig_id),
|
||||
asyncness,
|
||||
abi: sig.abi,
|
||||
}
|
||||
let sig = self.tcx.fn_sig(sig_id).skip_binder().skip_binder();
|
||||
let asyncness = match self.tcx.asyncness(sig_id) {
|
||||
Asyncness::Yes => hir::IsAsync::Async(span),
|
||||
Asyncness::No => hir::IsAsync::NotAsync,
|
||||
};
|
||||
|
||||
let header = hir::FnHeader {
|
||||
safety: if self.tcx.codegen_fn_attrs(sig_id).safe_target_features {
|
||||
hir::HeaderSafety::SafeTargetFeatures
|
||||
} else {
|
||||
hir::HeaderSafety::Normal(sig.safety)
|
||||
},
|
||||
constness: self.tcx.constness(sig_id),
|
||||
asyncness,
|
||||
abi: sig.abi,
|
||||
};
|
||||
|
||||
hir::FnSig { decl, header, span }
|
||||
@@ -550,7 +398,6 @@ fn generate_arg(
|
||||
fn lower_delegation_body(
|
||||
&mut self,
|
||||
delegation: &Delegation,
|
||||
item_id: NodeId,
|
||||
is_method: bool,
|
||||
param_count: usize,
|
||||
generics: &mut GenericsGenerationResults<'hir>,
|
||||
@@ -573,6 +420,7 @@ fn lower_delegation_body(
|
||||
resolver: this.resolver,
|
||||
path_id: delegation.id,
|
||||
self_param_id: pat_node_id,
|
||||
phantom: PhantomData,
|
||||
};
|
||||
self_resolver.visit_block(block);
|
||||
// Target expr needs to lower `self` path.
|
||||
@@ -584,7 +432,18 @@ fn lower_delegation_body(
|
||||
args.push(arg);
|
||||
}
|
||||
|
||||
let final_expr = this.finalize_body_lowering(delegation, item_id, args, generics, span);
|
||||
// If we have no params in signature function but user still wrote some code in
|
||||
// delegation body, then add this code as first arg, eventually an error will be shown,
|
||||
// also nested delegations may need to access information about this code (#154332),
|
||||
// so it is better to leave this code as opposed to bodies of extern functions,
|
||||
// which are completely erased from existence.
|
||||
if param_count == 0
|
||||
&& let Some(block) = block
|
||||
{
|
||||
args.push(this.lower_target_expr(&block));
|
||||
}
|
||||
|
||||
let final_expr = this.finalize_body_lowering(delegation, args, generics, span);
|
||||
|
||||
(this.arena.alloc_from_iter(parameters), final_expr)
|
||||
})
|
||||
@@ -621,7 +480,6 @@ fn lower_target_expr(&mut self, block: &Block) -> hir::Expr<'hir> {
|
||||
fn finalize_body_lowering(
|
||||
&mut self,
|
||||
delegation: &Delegation,
|
||||
item_id: NodeId,
|
||||
args: Vec<hir::Expr<'hir>>,
|
||||
generics: &mut GenericsGenerationResults<'hir>,
|
||||
span: Span,
|
||||
@@ -651,7 +509,7 @@ fn finalize_body_lowering(
|
||||
|
||||
// FIXME(fn_delegation): proper support for parent generics propagation
|
||||
// in method call scenario.
|
||||
let segment = self.process_segment(item_id, span, &segment, &mut generics.child, false);
|
||||
let segment = self.process_segment(span, &segment, &mut generics.child, false);
|
||||
let segment = self.arena.alloc(segment);
|
||||
|
||||
self.arena.alloc(hir::Expr {
|
||||
@@ -678,7 +536,7 @@ fn finalize_body_lowering(
|
||||
new_path.segments = self.arena.alloc_from_iter(
|
||||
new_path.segments.iter().enumerate().map(|(idx, segment)| {
|
||||
let mut process_segment = |result, add_lifetimes| {
|
||||
self.process_segment(item_id, span, segment, result, add_lifetimes)
|
||||
self.process_segment(span, segment, result, add_lifetimes)
|
||||
};
|
||||
|
||||
if idx + 2 == len {
|
||||
@@ -694,8 +552,7 @@ fn finalize_body_lowering(
|
||||
hir::QPath::Resolved(ty, self.arena.alloc(new_path))
|
||||
}
|
||||
hir::QPath::TypeRelative(ty, segment) => {
|
||||
let segment =
|
||||
self.process_segment(item_id, span, segment, &mut generics.child, false);
|
||||
let segment = self.process_segment(span, segment, &mut generics.child, false);
|
||||
|
||||
hir::QPath::TypeRelative(ty, self.arena.alloc(segment))
|
||||
}
|
||||
@@ -719,26 +576,26 @@ fn finalize_body_lowering(
|
||||
|
||||
fn process_segment(
|
||||
&mut self,
|
||||
item_id: NodeId,
|
||||
span: Span,
|
||||
segment: &hir::PathSegment<'hir>,
|
||||
result: &mut GenericsGenerationResult<'hir>,
|
||||
add_lifetimes: bool,
|
||||
) -> hir::PathSegment<'hir> {
|
||||
// The first condition is needed when there is SelfAndUserSpecified case,
|
||||
// we don't want to propagate generics params in this situation.
|
||||
let segment = if !result.generics.is_user_specified()
|
||||
&& let Some(args) = result
|
||||
.generics
|
||||
.into_hir_generics(self, item_id, span)
|
||||
.into_generic_args(self, add_lifetimes, span)
|
||||
{
|
||||
hir::PathSegment { args: Some(args), ..segment.clone() }
|
||||
let details = result.generics.args_propagation_details();
|
||||
|
||||
let segment = if details.should_propagate {
|
||||
let generics = result.generics.into_hir_generics(self, span);
|
||||
let args = generics.into_generic_args(self, add_lifetimes, span);
|
||||
|
||||
// Needed for better error messages (`trait-impl-wrong-args-count.rs` test).
|
||||
let args = if args.is_empty() { None } else { Some(args) };
|
||||
|
||||
hir::PathSegment { args, ..segment.clone() }
|
||||
} else {
|
||||
segment.clone()
|
||||
};
|
||||
|
||||
if result.generics.is_user_specified() {
|
||||
if details.use_args_in_sig_inheritance {
|
||||
result.args_segment_id = Some(segment.hir_id);
|
||||
}
|
||||
|
||||
@@ -816,25 +673,26 @@ fn mk_expr(&mut self, kind: hir::ExprKind<'hir>, span: Span) -> hir::Expr<'hir>
|
||||
}
|
||||
}
|
||||
|
||||
struct SelfResolver<'a, 'tcx> {
|
||||
resolver: &'a mut ResolverAstLowering<'tcx>,
|
||||
struct SelfResolver<'a, 'tcx, R> {
|
||||
resolver: &'a mut R,
|
||||
path_id: NodeId,
|
||||
self_param_id: NodeId,
|
||||
phantom: PhantomData<&'tcx ()>,
|
||||
}
|
||||
|
||||
impl SelfResolver<'_, '_> {
|
||||
impl<'tcx, R: ResolverAstLoweringExt<'tcx>> SelfResolver<'_, 'tcx, R> {
|
||||
fn try_replace_id(&mut self, id: NodeId) {
|
||||
if let Some(res) = self.resolver.partial_res_map.get(&id)
|
||||
if let Some(res) = self.resolver.get_partial_res(id)
|
||||
&& let Some(Res::Local(sig_id)) = res.full_res()
|
||||
&& sig_id == self.path_id
|
||||
{
|
||||
let new_res = PartialRes::new(Res::Local(self.self_param_id));
|
||||
self.resolver.partial_res_map.insert(id, new_res);
|
||||
self.resolver.insert_partial_res(id, new_res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, 'a> Visitor<'ast> for SelfResolver<'a, '_> {
|
||||
impl<'ast, 'a, 'tcx, R: ResolverAstLoweringExt<'tcx>> Visitor<'ast> for SelfResolver<'a, 'tcx, R> {
|
||||
fn visit_id(&mut self, id: NodeId) {
|
||||
self.try_replace_id(id);
|
||||
}
|
||||
|
||||
@@ -5,41 +5,42 @@
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::ty::GenericParamDefKind;
|
||||
use rustc_middle::{bug, ty};
|
||||
use rustc_span::sym::{self};
|
||||
use rustc_span::symbol::kw;
|
||||
use rustc_span::{DUMMY_SP, Ident, Span};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
use rustc_span::{Ident, Span};
|
||||
|
||||
use crate::{AstOwner, LoweringContext};
|
||||
use crate::{LoweringContext, ResolverAstLoweringExt};
|
||||
|
||||
pub(super) enum DelegationGenerics<T> {
|
||||
/// User-specified args are present: `reuse foo::<String>;`.
|
||||
UserSpecified,
|
||||
/// The default case when no user-specified args are present: `reuse Trait::foo;`.
|
||||
Default(Option<T>),
|
||||
Default(T),
|
||||
/// In free-to-trait reuse, when user specified args for trait `reuse Trait::<i32>::foo;`
|
||||
/// in this case we need to both generate `Self` and process user args.
|
||||
SelfAndUserSpecified(Option<T>),
|
||||
SelfAndUserSpecified(T),
|
||||
/// In delegations from trait impl to other entities like free functions or trait functions,
|
||||
/// we want to generate a function whose generics matches generics of signature function
|
||||
/// in trait.
|
||||
TraitImpl(T, bool /* Has user-specified args */),
|
||||
}
|
||||
|
||||
/// Used for storing either AST generics or their lowered HIR version. Firstly we obtain
|
||||
/// AST generics either from local function from AST index or from external function
|
||||
/// through `tcx`. Next, at some point of generics processing we need to lower those
|
||||
/// generics to HIR, for this purpose we use `into_hir_generics` that lowers AST generics
|
||||
/// and replaces Ast variant with Hir. Such approach is useful as we can call this method
|
||||
/// at any time knowing that lowering will occur at most only once. Then, in order to obtain generic
|
||||
/// Used for storing either ty generics or their uplifted HIR version. First we obtain
|
||||
/// ty generics. Next, at some point of generics processing we need to uplift those
|
||||
/// generics to HIR, for this purpose we use `into_hir_generics` that uplifts ty generics
|
||||
/// and replaces Ty variant with Hir. Such approach is useful as we can call this method
|
||||
/// at any time knowing that uplifting will occur at most only once. Then, in order to obtain generic
|
||||
/// params or args we use `hir_generics_or_empty` or `into_generic_args` functions.
|
||||
/// There also may be situations when we obtained AST generics but never lowered them to HIR,
|
||||
/// There also may be situations when we obtained ty generics but never uplifted them to HIR,
|
||||
/// meaning we did not propagate them and thus we do not need to generate generic params
|
||||
/// (i.e., method call scenarios), in such a case this approach helps
|
||||
/// a lot as if `into_hir_generics` will not be called then lowering will not happen.
|
||||
pub(super) enum HirOrAstGenerics<'hir> {
|
||||
Ast(DelegationGenerics<Generics>),
|
||||
/// a lot as if `into_hir_generics` will not be called then uplifting will not happen.
|
||||
pub(super) enum HirOrTyGenerics<'hir> {
|
||||
Ty(DelegationGenerics<&'hir [ty::GenericParamDef]>),
|
||||
Hir(DelegationGenerics<&'hir hir::Generics<'hir>>),
|
||||
}
|
||||
|
||||
pub(super) struct GenericsGenerationResult<'hir> {
|
||||
pub(super) generics: HirOrAstGenerics<'hir>,
|
||||
pub(super) generics: HirOrTyGenerics<'hir>,
|
||||
pub(super) args_segment_id: Option<HirId>,
|
||||
}
|
||||
|
||||
@@ -48,38 +49,57 @@ pub(super) struct GenericsGenerationResults<'hir> {
|
||||
pub(super) child: GenericsGenerationResult<'hir>,
|
||||
}
|
||||
|
||||
pub(super) struct GenericArgsPropagationDetails {
|
||||
pub(super) should_propagate: bool,
|
||||
pub(super) use_args_in_sig_inheritance: bool,
|
||||
}
|
||||
|
||||
impl<T> DelegationGenerics<T> {
|
||||
fn is_user_specified(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
DelegationGenerics::UserSpecified | DelegationGenerics::SelfAndUserSpecified { .. }
|
||||
)
|
||||
fn args_propagation_details(&self) -> GenericArgsPropagationDetails {
|
||||
match self {
|
||||
DelegationGenerics::UserSpecified | DelegationGenerics::SelfAndUserSpecified { .. } => {
|
||||
GenericArgsPropagationDetails {
|
||||
should_propagate: false,
|
||||
use_args_in_sig_inheritance: true,
|
||||
}
|
||||
}
|
||||
DelegationGenerics::TraitImpl(_, user_specified) => GenericArgsPropagationDetails {
|
||||
should_propagate: !*user_specified,
|
||||
use_args_in_sig_inheritance: false,
|
||||
},
|
||||
DelegationGenerics::Default(_) => GenericArgsPropagationDetails {
|
||||
should_propagate: true,
|
||||
use_args_in_sig_inheritance: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> HirOrAstGenerics<'hir> {
|
||||
impl<'hir> HirOrTyGenerics<'hir> {
|
||||
pub(super) fn into_hir_generics(
|
||||
&mut self,
|
||||
ctx: &mut LoweringContext<'_, 'hir>,
|
||||
item_id: NodeId,
|
||||
ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
|
||||
span: Span,
|
||||
) -> &mut HirOrAstGenerics<'hir> {
|
||||
if let HirOrAstGenerics::Ast(generics) = self {
|
||||
let process_params = |generics: &mut Generics| {
|
||||
ctx.lower_delegation_generic_params(item_id, span, &mut generics.params)
|
||||
) -> &mut HirOrTyGenerics<'hir> {
|
||||
if let HirOrTyGenerics::Ty(params) = self {
|
||||
let mut uplift_params = |generics: &'hir [ty::GenericParamDef]| {
|
||||
ctx.uplift_delegation_generic_params(span, generics)
|
||||
};
|
||||
|
||||
let hir_generics = match generics {
|
||||
let hir_generics = match params {
|
||||
DelegationGenerics::UserSpecified => DelegationGenerics::UserSpecified,
|
||||
DelegationGenerics::Default(generics) => {
|
||||
DelegationGenerics::Default(generics.as_mut().map(process_params))
|
||||
DelegationGenerics::Default(params) => {
|
||||
DelegationGenerics::Default(uplift_params(params))
|
||||
}
|
||||
DelegationGenerics::SelfAndUserSpecified(generics) => {
|
||||
DelegationGenerics::SelfAndUserSpecified(generics.as_mut().map(process_params))
|
||||
DelegationGenerics::SelfAndUserSpecified(params) => {
|
||||
DelegationGenerics::SelfAndUserSpecified(uplift_params(params))
|
||||
}
|
||||
DelegationGenerics::TraitImpl(params, user_specified) => {
|
||||
DelegationGenerics::TraitImpl(uplift_params(params), *user_specified)
|
||||
}
|
||||
};
|
||||
|
||||
*self = HirOrAstGenerics::Hir(hir_generics);
|
||||
*self = HirOrTyGenerics::Hir(hir_generics);
|
||||
}
|
||||
|
||||
self
|
||||
@@ -87,81 +107,72 @@ pub(super) fn into_hir_generics(
|
||||
|
||||
fn hir_generics_or_empty(&self) -> &'hir hir::Generics<'hir> {
|
||||
match self {
|
||||
HirOrAstGenerics::Ast(_) => hir::Generics::empty(),
|
||||
HirOrAstGenerics::Hir(hir_generics) => match hir_generics {
|
||||
HirOrTyGenerics::Ty(_) => hir::Generics::empty(),
|
||||
HirOrTyGenerics::Hir(hir_generics) => match hir_generics {
|
||||
DelegationGenerics::UserSpecified => hir::Generics::empty(),
|
||||
DelegationGenerics::Default(generics)
|
||||
| DelegationGenerics::SelfAndUserSpecified(generics) => {
|
||||
generics.unwrap_or(hir::Generics::empty())
|
||||
}
|
||||
| DelegationGenerics::SelfAndUserSpecified(generics)
|
||||
| DelegationGenerics::TraitImpl(generics, _) => generics,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn into_generic_args(
|
||||
&self,
|
||||
ctx: &mut LoweringContext<'_, 'hir>,
|
||||
ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
|
||||
add_lifetimes: bool,
|
||||
span: Span,
|
||||
) -> Option<&'hir hir::GenericArgs<'hir>> {
|
||||
) -> &'hir hir::GenericArgs<'hir> {
|
||||
match self {
|
||||
HirOrAstGenerics::Ast(_) => {
|
||||
bug!("Attempting to get generic args before lowering to HIR")
|
||||
HirOrTyGenerics::Ty(_) => {
|
||||
bug!("Attempting to get generic args before uplifting to HIR")
|
||||
}
|
||||
HirOrAstGenerics::Hir(hir_generics) => match hir_generics {
|
||||
DelegationGenerics::UserSpecified => None,
|
||||
HirOrTyGenerics::Hir(hir_generics) => match hir_generics {
|
||||
DelegationGenerics::UserSpecified => hir::GenericArgs::NONE,
|
||||
DelegationGenerics::Default(generics)
|
||||
| DelegationGenerics::SelfAndUserSpecified(generics) => generics.map(|generics| {
|
||||
| DelegationGenerics::SelfAndUserSpecified(generics)
|
||||
| DelegationGenerics::TraitImpl(generics, _) => {
|
||||
ctx.create_generics_args_from_params(generics.params, add_lifetimes, span)
|
||||
}),
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn is_user_specified(&self) -> bool {
|
||||
pub(super) fn args_propagation_details(&self) -> GenericArgsPropagationDetails {
|
||||
match self {
|
||||
HirOrAstGenerics::Ast(ast_generics) => ast_generics.is_user_specified(),
|
||||
HirOrAstGenerics::Hir(hir_generics) => hir_generics.is_user_specified(),
|
||||
HirOrTyGenerics::Ty(ty_generics) => ty_generics.args_propagation_details(),
|
||||
HirOrTyGenerics::Hir(hir_generics) => hir_generics.args_propagation_details(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> GenericsGenerationResult<'a> {
|
||||
fn new(generics: DelegationGenerics<Generics>) -> GenericsGenerationResult<'a> {
|
||||
GenericsGenerationResult {
|
||||
generics: HirOrAstGenerics::Ast(generics),
|
||||
args_segment_id: None,
|
||||
}
|
||||
impl<'hir> GenericsGenerationResult<'hir> {
|
||||
fn new(
|
||||
generics: DelegationGenerics<&'hir [ty::GenericParamDef]>,
|
||||
) -> GenericsGenerationResult<'hir> {
|
||||
GenericsGenerationResult { generics: HirOrTyGenerics::Ty(generics), args_segment_id: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> GenericsGenerationResults<'hir> {
|
||||
pub(super) fn all_params(
|
||||
&mut self,
|
||||
item_id: NodeId,
|
||||
span: Span,
|
||||
ctx: &mut LoweringContext<'_, 'hir>,
|
||||
ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
|
||||
) -> impl Iterator<Item = hir::GenericParam<'hir>> {
|
||||
// Now we always call `into_hir_generics` both on child and parent,
|
||||
// however in future we would not do that, when scenarios like
|
||||
// method call will be supported (if HIR generics were not obtained
|
||||
// then it means that we did not propagated them, thus we do not need
|
||||
// to generate params).
|
||||
let parent = self
|
||||
.parent
|
||||
.generics
|
||||
.into_hir_generics(ctx, item_id, span)
|
||||
.hir_generics_or_empty()
|
||||
.params;
|
||||
let mut create_params = |result: &mut GenericsGenerationResult<'hir>| {
|
||||
result.generics.into_hir_generics(ctx, span).hir_generics_or_empty().params
|
||||
};
|
||||
|
||||
let child = self
|
||||
.child
|
||||
.generics
|
||||
.into_hir_generics(ctx, item_id, span)
|
||||
.hir_generics_or_empty()
|
||||
.params;
|
||||
let parent = create_params(&mut self.parent);
|
||||
let child = create_params(&mut self.child);
|
||||
|
||||
// Order generics, firstly we have parent and child lifetimes,
|
||||
// Order generics, first we have parent and child lifetimes,
|
||||
// then parent and child types and consts.
|
||||
// `generics_of` in `rustc_hir_analysis` will order them anyway,
|
||||
// however we want the order to be consistent in HIR too.
|
||||
@@ -174,92 +185,94 @@ pub(super) fn all_params(
|
||||
.copied()
|
||||
}
|
||||
|
||||
/// As we add hack predicates(`'a: 'a`) for all lifetimes (see `lower_delegation_generic_params`
|
||||
/// As we add hack predicates(`'a: 'a`) for all lifetimes (see `uplift_delegation_generic_params`
|
||||
/// and `generate_lifetime_predicate` functions) we need to add them to delegation generics.
|
||||
/// Those predicates will not affect resulting predicate inheritance and folding
|
||||
/// in `rustc_hir_analysis`, as we inherit all predicates from delegation signature.
|
||||
pub(super) fn all_predicates(
|
||||
&mut self,
|
||||
item_id: NodeId,
|
||||
span: Span,
|
||||
ctx: &mut LoweringContext<'_, 'hir>,
|
||||
ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
|
||||
) -> impl Iterator<Item = hir::WherePredicate<'hir>> {
|
||||
// Now we always call `into_hir_generics` both on child and parent,
|
||||
// however in future we would not do that, when scenarios like
|
||||
// method call will be supported (if HIR generics were not obtained
|
||||
// then it means that we did not propagated them, thus we do not need
|
||||
// to generate predicates).
|
||||
self.parent
|
||||
.generics
|
||||
.into_hir_generics(ctx, item_id, span)
|
||||
.hir_generics_or_empty()
|
||||
.predicates
|
||||
.into_iter()
|
||||
.chain(
|
||||
self.child
|
||||
.generics
|
||||
.into_hir_generics(ctx, item_id, span)
|
||||
.hir_generics_or_empty()
|
||||
.predicates
|
||||
.into_iter(),
|
||||
)
|
||||
.copied()
|
||||
let mut create_predicates = |result: &mut GenericsGenerationResult<'hir>| {
|
||||
result.generics.into_hir_generics(ctx, span).hir_generics_or_empty().predicates
|
||||
};
|
||||
|
||||
let parent = create_predicates(&mut self.parent);
|
||||
let child = create_predicates(&mut self.child);
|
||||
|
||||
parent.into_iter().chain(child).copied()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
pub(super) fn lower_delegation_generics(
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
pub(super) fn uplift_delegation_generics(
|
||||
&mut self,
|
||||
delegation: &Delegation,
|
||||
root_fn_id: DefId,
|
||||
sig_id: DefId,
|
||||
item_id: NodeId,
|
||||
span: Span,
|
||||
) -> GenericsGenerationResults<'hir> {
|
||||
let delegation_in_free_ctx = !matches!(
|
||||
self.tcx.def_kind(self.tcx.local_parent(self.local_def_id(item_id))),
|
||||
DefKind::Trait | DefKind::Impl { .. }
|
||||
);
|
||||
|
||||
let root_function_in_trait =
|
||||
matches!(self.tcx.def_kind(self.tcx.parent(root_fn_id)), DefKind::Trait);
|
||||
|
||||
let generate_self = delegation_in_free_ctx && root_function_in_trait;
|
||||
|
||||
let parent_generics_factory = |this: &mut Self, user_specified: bool| {
|
||||
this.get_parent_generics(
|
||||
this.tcx.parent(root_fn_id),
|
||||
generate_self,
|
||||
user_specified,
|
||||
span,
|
||||
)
|
||||
};
|
||||
let delegation_parent_kind =
|
||||
self.tcx.def_kind(self.tcx.local_parent(self.local_def_id(item_id)));
|
||||
|
||||
let segments = &delegation.path.segments;
|
||||
let len = segments.len();
|
||||
let child_user_specified = segments[len - 1].args.is_some();
|
||||
|
||||
let sig_params = &self.tcx.generics_of(sig_id).own_params[..];
|
||||
|
||||
// If we are in trait impl always generate function whose generics matches
|
||||
// those that are defined in trait.
|
||||
if matches!(delegation_parent_kind, DefKind::Impl { of_trait: true }) {
|
||||
// Considering parent generics, during signature inheritance
|
||||
// we will take those args that are in trait impl header trait ref.
|
||||
let parent = GenericsGenerationResult::new(DelegationGenerics::TraitImpl(&[], true));
|
||||
|
||||
let child = DelegationGenerics::TraitImpl(sig_params, child_user_specified);
|
||||
let child = GenericsGenerationResult::new(child);
|
||||
|
||||
return GenericsGenerationResults { parent, child };
|
||||
}
|
||||
|
||||
let delegation_in_free_ctx =
|
||||
!matches!(delegation_parent_kind, DefKind::Trait | DefKind::Impl { .. });
|
||||
|
||||
let sig_parent = self.tcx.parent(sig_id);
|
||||
let sig_in_trait = matches!(self.tcx.def_kind(sig_parent), DefKind::Trait);
|
||||
|
||||
let can_add_generics_to_parent = len >= 2
|
||||
&& self.get_resolution_id(segments[len - 2].id).is_some_and(|def_id| {
|
||||
matches!(self.tcx.def_kind(def_id), DefKind::Trait | DefKind::TraitAlias)
|
||||
});
|
||||
|
||||
let generate_self = delegation_in_free_ctx && sig_in_trait;
|
||||
let parent_generics = if can_add_generics_to_parent {
|
||||
let sig_parent_params = &self.tcx.generics_of(sig_parent).own_params[..];
|
||||
|
||||
if segments[len - 2].args.is_some() {
|
||||
if generate_self {
|
||||
DelegationGenerics::SelfAndUserSpecified(parent_generics_factory(self, true))
|
||||
// Take only first Self parameter, it is trait so Self must be present.
|
||||
DelegationGenerics::SelfAndUserSpecified(&sig_parent_params[..1])
|
||||
} else {
|
||||
DelegationGenerics::UserSpecified
|
||||
}
|
||||
} else {
|
||||
DelegationGenerics::Default(parent_generics_factory(self, false))
|
||||
let skip_self = usize::from(!generate_self);
|
||||
DelegationGenerics::Default(&sig_parent_params[skip_self..])
|
||||
}
|
||||
} else {
|
||||
DelegationGenerics::Default(None)
|
||||
DelegationGenerics::<&'hir [ty::GenericParamDef]>::Default(&[])
|
||||
};
|
||||
|
||||
let child_generics = if segments[len - 1].args.is_some() {
|
||||
let child_generics = if child_user_specified {
|
||||
DelegationGenerics::UserSpecified
|
||||
} else {
|
||||
DelegationGenerics::Default(self.get_fn_like_generics(root_fn_id, span))
|
||||
DelegationGenerics::Default(sig_params)
|
||||
};
|
||||
|
||||
GenericsGenerationResults {
|
||||
@@ -268,61 +281,70 @@ pub(super) fn lower_delegation_generics(
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_delegation_generic_params(
|
||||
fn uplift_delegation_generic_params(
|
||||
&mut self,
|
||||
item_id: NodeId,
|
||||
span: Span,
|
||||
params: &mut ThinVec<GenericParam>,
|
||||
params: &'hir [ty::GenericParamDef],
|
||||
) -> &'hir hir::Generics<'hir> {
|
||||
for p in params.iter_mut() {
|
||||
// We want to create completely new params, so we generate
|
||||
// a new id, otherwise assertions will be triggered.
|
||||
p.id = self.next_node_id();
|
||||
let params = self.arena.alloc_from_iter(params.iter().map(|p| {
|
||||
let def_kind = match p.kind {
|
||||
GenericParamDefKind::Lifetime => DefKind::LifetimeParam,
|
||||
GenericParamDefKind::Type { .. } => DefKind::TyParam,
|
||||
GenericParamDefKind::Const { .. } => DefKind::ConstParam,
|
||||
};
|
||||
|
||||
// Remove default params, as they are not supported on functions
|
||||
// and there will duplicate DefId when we try to lower them later.
|
||||
match &mut p.kind {
|
||||
GenericParamKind::Lifetime => {}
|
||||
GenericParamKind::Type { default } => *default = None,
|
||||
GenericParamKind::Const { default, .. } => *default = None,
|
||||
let param_ident = Ident::new(p.name, span);
|
||||
let def_name = Some(param_ident.name);
|
||||
let path_data = def_kind.def_path_data(def_name);
|
||||
let node_id = self.next_node_id();
|
||||
|
||||
let def_id = self.create_def(node_id, def_name, def_kind, path_data, span);
|
||||
|
||||
let kind = match p.kind {
|
||||
GenericParamDefKind::Lifetime => {
|
||||
hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }
|
||||
}
|
||||
GenericParamDefKind::Type { synthetic, .. } => {
|
||||
hir::GenericParamKind::Type { default: None, synthetic }
|
||||
}
|
||||
GenericParamDefKind::Const { .. } => {
|
||||
let hir_id = self.next_id();
|
||||
let kind = hir::TyKind::InferDelegation(hir::InferDelegation::DefId(p.def_id));
|
||||
|
||||
hir::GenericParamKind::Const {
|
||||
ty: self.arena.alloc(hir::Ty { kind, hir_id, span }),
|
||||
default: None,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Important: we don't use `self.next_id()` as we want to execute
|
||||
// `lower_node_id` routine so param's id is added to `self.children`.
|
||||
let hir_id = self.lower_node_id(node_id);
|
||||
|
||||
hir::GenericParam {
|
||||
hir_id,
|
||||
colon_span: Some(span),
|
||||
def_id,
|
||||
kind,
|
||||
name: hir::ParamName::Plain(param_ident),
|
||||
pure_wrt_drop: p.pure_wrt_drop,
|
||||
source: hir::GenericParamSource::Generics,
|
||||
span,
|
||||
}
|
||||
|
||||
// Note that we use self.disambiguator here, if we will create new every time
|
||||
// we will get ICE if params have the same name.
|
||||
self.resolver.node_id_to_def_id.insert(
|
||||
p.id,
|
||||
self.tcx
|
||||
.create_def(
|
||||
self.resolver.node_id_to_def_id[&item_id],
|
||||
Some(p.ident.name),
|
||||
match p.kind {
|
||||
GenericParamKind::Lifetime => DefKind::LifetimeParam,
|
||||
GenericParamKind::Type { .. } => DefKind::TyParam,
|
||||
GenericParamKind::Const { .. } => DefKind::ConstParam,
|
||||
},
|
||||
None,
|
||||
&mut self.disambiguator,
|
||||
)
|
||||
.def_id(),
|
||||
);
|
||||
}
|
||||
|
||||
// Fallback to default generic param lowering, we modified them in the loop above.
|
||||
let params = self.arena.alloc_from_iter(
|
||||
params.iter().map(|p| self.lower_generic_param(p, hir::GenericParamSource::Generics)),
|
||||
);
|
||||
}));
|
||||
|
||||
// HACK: for now we generate predicates such that all lifetimes are early bound,
|
||||
// we can not not generate early-bound lifetimes, but we can't know which of them
|
||||
// are late-bound at this level of compilation.
|
||||
// FIXME(fn_delegation): proper support for late bound lifetimes.
|
||||
let predicates =
|
||||
self.arena.alloc_from_iter(params.iter().filter_map(|p| {
|
||||
p.is_lifetime().then(|| self.generate_lifetime_predicate(p, span))
|
||||
}));
|
||||
|
||||
self.arena.alloc(hir::Generics {
|
||||
params,
|
||||
predicates: self.arena.alloc_from_iter(
|
||||
params
|
||||
.iter()
|
||||
.filter_map(|p| p.is_lifetime().then(|| self.generate_lifetime_predicate(p))),
|
||||
),
|
||||
predicates,
|
||||
has_where_clause_predicates: false,
|
||||
where_clause_span: span,
|
||||
span,
|
||||
@@ -332,22 +354,21 @@ fn lower_delegation_generic_params(
|
||||
fn generate_lifetime_predicate(
|
||||
&mut self,
|
||||
p: &hir::GenericParam<'hir>,
|
||||
span: Span,
|
||||
) -> hir::WherePredicate<'hir> {
|
||||
let create_lifetime = |this: &mut Self| -> &'hir hir::Lifetime {
|
||||
this.arena.alloc(hir::Lifetime {
|
||||
hir_id: this.next_id(),
|
||||
ident: p.name.ident(),
|
||||
kind: rustc_hir::LifetimeKind::Param(p.def_id),
|
||||
source: rustc_hir::LifetimeSource::Path {
|
||||
angle_brackets: rustc_hir::AngleBrackets::Full,
|
||||
},
|
||||
syntax: rustc_hir::LifetimeSyntax::ExplicitBound,
|
||||
kind: hir::LifetimeKind::Param(p.def_id),
|
||||
source: hir::LifetimeSource::Path { angle_brackets: hir::AngleBrackets::Full },
|
||||
syntax: hir::LifetimeSyntax::ExplicitBound,
|
||||
})
|
||||
};
|
||||
|
||||
hir::WherePredicate {
|
||||
hir_id: self.next_id(),
|
||||
span: DUMMY_SP,
|
||||
span,
|
||||
kind: self.arena.alloc(hir::WherePredicateKind::RegionPredicate(
|
||||
hir::WhereRegionPredicate {
|
||||
in_where_clause: true,
|
||||
@@ -369,7 +390,7 @@ fn create_generics_args_from_params(
|
||||
self.arena.alloc(hir::GenericArgs {
|
||||
args: self.arena.alloc_from_iter(params.iter().filter_map(|p| {
|
||||
// Skip self generic arg, we do not need to propagate it.
|
||||
if p.name.ident().name == kw::SelfUpper {
|
||||
if p.name.ident().name == kw::SelfUpper || p.is_impl_trait() {
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -433,146 +454,4 @@ fn create_generics_args_from_params(
|
||||
span_ext: span,
|
||||
})
|
||||
}
|
||||
|
||||
fn get_fn_like_generics(&mut self, id: DefId, span: Span) -> Option<Generics> {
|
||||
if let Some(local_id) = id.as_local() {
|
||||
match self.ast_index.get(local_id) {
|
||||
Some(AstOwner::Item(item)) if let ItemKind::Fn(f) = &item.kind => {
|
||||
Some(f.generics.clone())
|
||||
}
|
||||
Some(AstOwner::AssocItem(item, _)) if let AssocItemKind::Fn(f) = &item.kind => {
|
||||
Some(f.generics.clone())
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
self.get_external_generics(id, false, span)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_external_generics(
|
||||
&mut self,
|
||||
id: DefId,
|
||||
processing_parent: bool,
|
||||
span: Span,
|
||||
) -> Option<Generics> {
|
||||
let generics = self.tcx.generics_of(id);
|
||||
if generics.own_params.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Skip first Self parameter if we are in trait, it will be added later.
|
||||
let to_skip = (processing_parent && generics.has_self) as usize;
|
||||
|
||||
Some(Generics {
|
||||
params: generics
|
||||
.own_params
|
||||
.iter()
|
||||
.skip(to_skip)
|
||||
.map(|p| GenericParam {
|
||||
attrs: Default::default(),
|
||||
bounds: Default::default(),
|
||||
colon_span: None,
|
||||
id: self.next_node_id(),
|
||||
ident: Ident::with_dummy_span(p.name),
|
||||
is_placeholder: false,
|
||||
kind: match p.kind {
|
||||
GenericParamDefKind::Lifetime => GenericParamKind::Lifetime,
|
||||
GenericParamDefKind::Type { .. } => {
|
||||
GenericParamKind::Type { default: None }
|
||||
}
|
||||
GenericParamDefKind::Const { .. } => self.map_const_kind(p, span),
|
||||
},
|
||||
})
|
||||
.collect(),
|
||||
where_clause: Default::default(),
|
||||
span: DUMMY_SP,
|
||||
})
|
||||
}
|
||||
|
||||
fn map_const_kind(&mut self, p: &ty::GenericParamDef, span: Span) -> GenericParamKind {
|
||||
let const_type = self.tcx.type_of(p.def_id).instantiate_identity();
|
||||
|
||||
let (type_symbol, res) = match const_type.kind() {
|
||||
ty::Bool => (sym::bool, Res::PrimTy(hir::PrimTy::Bool)),
|
||||
ty::Uint(uint) => (uint.name(), Res::PrimTy(hir::PrimTy::Uint(*uint))),
|
||||
ty::Int(int) => (int.name(), Res::PrimTy(hir::PrimTy::Int(*int))),
|
||||
ty::Char => (sym::char, Res::PrimTy(hir::PrimTy::Char)),
|
||||
_ => {
|
||||
self.tcx
|
||||
.dcx()
|
||||
.span_delayed_bug(span, format!("Unexpected const type: {}", const_type));
|
||||
|
||||
(sym::dummy, Res::Err)
|
||||
}
|
||||
};
|
||||
|
||||
let node_id = self.next_node_id();
|
||||
|
||||
self.resolver.partial_res_map.insert(node_id, hir::def::PartialRes::new(res));
|
||||
|
||||
GenericParamKind::Const {
|
||||
ty: Box::new(Ty {
|
||||
id: node_id,
|
||||
kind: TyKind::Path(
|
||||
None,
|
||||
Path {
|
||||
segments: thin_vec![PathSegment {
|
||||
ident: Ident::with_dummy_span(type_symbol),
|
||||
id: self.next_node_id(),
|
||||
args: None
|
||||
}],
|
||||
span: DUMMY_SP,
|
||||
tokens: None,
|
||||
},
|
||||
),
|
||||
span: DUMMY_SP,
|
||||
tokens: None,
|
||||
}),
|
||||
span: DUMMY_SP,
|
||||
default: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_parent_generics(
|
||||
&mut self,
|
||||
id: DefId,
|
||||
add_self: bool,
|
||||
user_specified: bool,
|
||||
span: Span,
|
||||
) -> Option<Generics> {
|
||||
// If args are user-specified we still maybe need to add self.
|
||||
let mut generics = if user_specified {
|
||||
None
|
||||
} else {
|
||||
if let Some(local_id) = id.as_local() {
|
||||
if let Some(AstOwner::Item(item)) = self.ast_index.get(local_id)
|
||||
&& matches!(item.kind, ItemKind::Trait(..))
|
||||
{
|
||||
item.opt_generics().cloned()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
self.get_external_generics(id, true, span)
|
||||
}
|
||||
};
|
||||
|
||||
if add_self {
|
||||
generics.get_or_insert_default().params.insert(
|
||||
0,
|
||||
GenericParam {
|
||||
id: self.next_node_id(),
|
||||
ident: Ident::new(kw::SelfUpper, DUMMY_SP),
|
||||
attrs: Default::default(),
|
||||
bounds: vec![],
|
||||
is_placeholder: false,
|
||||
kind: GenericParamKind::Type { default: None },
|
||||
colon_span: None,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
generics
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use rustc_errors::DiagArgFromDisplay;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{DiagArgFromDisplay, DiagSymbolList};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_span::{Ident, Span, Symbol};
|
||||
|
||||
@@ -191,10 +191,10 @@ pub(crate) struct ClobberAbiNotSupported {
|
||||
#[derive(Diagnostic)]
|
||||
#[note("the following ABIs are supported on this target: {$supported_abis}")]
|
||||
#[diag("invalid ABI for `clobber_abi`")]
|
||||
pub(crate) struct InvalidAbiClobberAbi {
|
||||
pub(crate) struct InvalidAbiClobberAbi<'a> {
|
||||
#[primary_span]
|
||||
pub abi_span: Span,
|
||||
pub supported_abis: String,
|
||||
pub supported_abis: DiagSymbolList<&'a str>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
@@ -215,17 +215,18 @@ pub(crate) struct InvalidRegisterClass {
|
||||
#[primary_span]
|
||||
pub op_span: Span,
|
||||
pub reg_class: Symbol,
|
||||
pub supported_register_classes: String,
|
||||
pub supported_register_classes: DiagSymbolList<Symbol>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("invalid asm template modifier for this register class")]
|
||||
#[diag("invalid asm template modifier `{$modifier}` for this register class")]
|
||||
pub(crate) struct InvalidAsmTemplateModifierRegClass {
|
||||
#[primary_span]
|
||||
#[label("template modifier")]
|
||||
pub placeholder_span: Span,
|
||||
#[label("argument")]
|
||||
pub op_span: Span,
|
||||
pub modifier: String,
|
||||
#[subdiagnostic]
|
||||
pub sub: InvalidAsmTemplateModifierRegClassSub,
|
||||
}
|
||||
@@ -235,7 +236,7 @@ pub(crate) enum InvalidAsmTemplateModifierRegClassSub {
|
||||
#[note(
|
||||
"the `{$class_name}` register class supports the following template modifiers: {$modifiers}"
|
||||
)]
|
||||
SupportModifier { class_name: Symbol, modifiers: String },
|
||||
SupportModifier { class_name: Symbol, modifiers: DiagSymbolList<char> },
|
||||
#[note("the `{$class_name}` register class does not support template modifiers")]
|
||||
DoesNotSupportModifier { class_name: Symbol },
|
||||
}
|
||||
|
||||
@@ -13,8 +13,7 @@
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::errors::report_lit_error;
|
||||
use rustc_span::source_map::{Spanned, respan};
|
||||
use rustc_span::{ByteSymbol, DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym};
|
||||
use rustc_span::{ByteSymbol, DUMMY_SP, DesugaringKind, Ident, Span, Spanned, Symbol, respan, sym};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
use visit::{Visitor, walk_expr};
|
||||
|
||||
@@ -53,7 +52,7 @@ fn visit_expr(&mut self, ex: &'v Expr) -> Self::Result {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
fn lower_exprs(&mut self, exprs: &[Box<Expr>]) -> &'hir [hir::Expr<'hir>] {
|
||||
self.arena.alloc_from_iter(exprs.iter().map(|x| self.lower_expr_mut(x)))
|
||||
}
|
||||
@@ -231,6 +230,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
|
||||
e.id,
|
||||
expr_hir_id,
|
||||
*coroutine_kind,
|
||||
*constness,
|
||||
fn_decl,
|
||||
body,
|
||||
*fn_decl_span,
|
||||
@@ -640,7 +640,7 @@ fn wrap_in_try_constructor(
|
||||
|
||||
fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {
|
||||
let pat = self.lower_pat(&arm.pat);
|
||||
let guard = arm.guard.as_ref().map(|cond| self.lower_expr(cond));
|
||||
let guard = arm.guard.as_ref().map(|guard| self.lower_expr(&guard.cond));
|
||||
let hir_id = self.next_id();
|
||||
let span = self.lower_span(arm.span);
|
||||
self.lower_attrs(hir_id, &arm.attrs, arm.span, Target::Arm);
|
||||
@@ -663,7 +663,7 @@ fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {
|
||||
} else if let Some(body) = &arm.body {
|
||||
self.dcx().emit_err(NeverPatternWithBody { span: body.span });
|
||||
} else if let Some(g) = &arm.guard {
|
||||
self.dcx().emit_err(NeverPatternWithGuard { span: g.span });
|
||||
self.dcx().emit_err(NeverPatternWithGuard { span: g.span() });
|
||||
}
|
||||
|
||||
// We add a fake `loop {}` arm body so that it typecks to `!`. The mir lowering of never
|
||||
@@ -1061,7 +1061,7 @@ fn lower_expr_closure(
|
||||
binder: &ClosureBinder,
|
||||
capture_clause: CaptureBy,
|
||||
closure_id: NodeId,
|
||||
constness: Const,
|
||||
mut constness: Const,
|
||||
movability: Movability,
|
||||
decl: &FnDecl,
|
||||
body: &Expr,
|
||||
@@ -1071,11 +1071,18 @@ fn lower_expr_closure(
|
||||
let closure_def_id = self.local_def_id(closure_id);
|
||||
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
|
||||
|
||||
if let Const::Yes(span) = constness {
|
||||
if !self.is_in_const_context {
|
||||
self.dcx().span_err(span, "cannot use `const` closures outside of const contexts");
|
||||
constness = Const::No;
|
||||
}
|
||||
}
|
||||
|
||||
let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| {
|
||||
let mut coroutine_kind = find_attr!(attrs, Coroutine(_) => hir::CoroutineKind::Coroutine(Movability::Movable));
|
||||
|
||||
// FIXME(contracts): Support contracts on closures?
|
||||
let body_id = this.lower_fn_body(decl, None, |this| {
|
||||
let body_id = this.lower_fn_body(decl, None, constness, |this| {
|
||||
this.coroutine_kind = coroutine_kind;
|
||||
let e = this.lower_expr_mut(body);
|
||||
coroutine_kind = this.coroutine_kind;
|
||||
@@ -1158,6 +1165,7 @@ fn lower_expr_coroutine_closure(
|
||||
closure_id: NodeId,
|
||||
closure_hir_id: HirId,
|
||||
coroutine_kind: CoroutineKind,
|
||||
constness: Const,
|
||||
decl: &FnDecl,
|
||||
body: &Expr,
|
||||
fn_decl_span: Span,
|
||||
@@ -1204,6 +1212,10 @@ fn lower_expr_coroutine_closure(
|
||||
let fn_decl =
|
||||
self.lower_fn_decl(&decl, closure_id, fn_decl_span, FnDeclKind::Closure, None);
|
||||
|
||||
if let Const::Yes(span) = constness {
|
||||
self.dcx().span_err(span, "const coroutines are not supported");
|
||||
}
|
||||
|
||||
let c = self.arena.alloc(hir::Closure {
|
||||
def_id: closure_def_id,
|
||||
binder: binder_clause,
|
||||
@@ -1217,7 +1229,7 @@ fn lower_expr_coroutine_closure(
|
||||
// knows that a `FnDecl` output type like `-> &str` actually means
|
||||
// "coroutine that returns &str", rather than directly returning a `&str`.
|
||||
kind: hir::ClosureKind::CoroutineClosure(coroutine_desugaring),
|
||||
constness: hir::Constness::NotConst,
|
||||
constness: self.lower_constness(constness),
|
||||
});
|
||||
hir::ExprKind::Closure(c)
|
||||
}
|
||||
@@ -1232,7 +1244,10 @@ fn lower_expr_assign(
|
||||
whole_span: Span,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
// Return early in case of an ordinary assignment.
|
||||
fn is_ordinary(lower_ctx: &mut LoweringContext<'_, '_>, lhs: &Expr) -> bool {
|
||||
fn is_ordinary<'hir>(
|
||||
lower_ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
|
||||
lhs: &Expr,
|
||||
) -> bool {
|
||||
match &lhs.kind {
|
||||
ExprKind::Array(..)
|
||||
| ExprKind::Struct(..)
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
use rustc_span::{ByteSymbol, DesugaringKind, Ident, Span, Symbol, sym};
|
||||
|
||||
use super::LoweringContext;
|
||||
use crate::ResolverAstLoweringExt;
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
pub(crate) fn lower_format_args(&mut self, sp: Span, fmt: &FormatArgs) -> hir::ExprKind<'hir> {
|
||||
// Never call the const constructor of `fmt::Arguments` if the
|
||||
// format_args!() had any arguments _before_ flattening/inlining.
|
||||
@@ -230,7 +231,7 @@ enum ArgumentType {
|
||||
/// <core::fmt::Argument>::new_…(arg)
|
||||
/// ```
|
||||
fn make_argument<'hir>(
|
||||
ctx: &mut LoweringContext<'_, 'hir>,
|
||||
ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
|
||||
sp: Span,
|
||||
arg: &'hir hir::Expr<'hir>,
|
||||
ty: ArgumentType,
|
||||
@@ -277,7 +278,7 @@ fn make_count(
|
||||
}
|
||||
|
||||
fn expand_format_args<'hir>(
|
||||
ctx: &mut LoweringContext<'_, 'hir>,
|
||||
ctx: &mut LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
|
||||
macsp: Span,
|
||||
fmt: &FormatArgs,
|
||||
allow_const: bool,
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
use std::mem;
|
||||
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_ast::visit::AssocCtxt;
|
||||
use rustc_ast::*;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err};
|
||||
use rustc_hir::attrs::{AttributeKind, EiiImplResolution};
|
||||
use rustc_hir::def::{DefKind, PerNS, Res};
|
||||
@@ -10,7 +13,7 @@
|
||||
};
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym};
|
||||
@@ -25,11 +28,31 @@
|
||||
RelaxedBoundForbiddenReason, RelaxedBoundPolicy, ResolverAstLoweringExt,
|
||||
};
|
||||
|
||||
pub(super) struct ItemLowerer<'a, 'hir> {
|
||||
/// Wraps either IndexVec (during `hir_crate`), which acts like a primary
|
||||
/// storage for most of the MaybeOwners, or FxIndexMap during delayed AST -> HIR
|
||||
/// lowering of delegations (`lower_delayed_owner`),
|
||||
/// in this case we can not modify already created IndexVec, so we use other map.
|
||||
pub(super) enum Owners<'a, 'hir> {
|
||||
IndexVec(&'a mut IndexVec<LocalDefId, hir::MaybeOwner<'hir>>),
|
||||
Map(&'a mut FxIndexMap<LocalDefId, hir::MaybeOwner<'hir>>),
|
||||
}
|
||||
|
||||
impl<'hir> Owners<'_, 'hir> {
|
||||
fn get_or_insert_mut(&mut self, def_id: LocalDefId) -> &mut hir::MaybeOwner<'hir> {
|
||||
match self {
|
||||
Owners::IndexVec(index_vec) => {
|
||||
index_vec.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom)
|
||||
}
|
||||
Owners::Map(map) => map.entry(def_id).or_insert(hir::MaybeOwner::Phantom),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct ItemLowerer<'a, 'hir, R> {
|
||||
pub(super) tcx: TyCtxt<'hir>,
|
||||
pub(super) resolver: &'a mut ResolverAstLowering<'hir>,
|
||||
pub(super) resolver: &'a mut R,
|
||||
pub(super) ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
|
||||
pub(super) owners: &'a mut IndexVec<LocalDefId, hir::MaybeOwner<'hir>>,
|
||||
pub(super) owners: Owners<'a, 'hir>,
|
||||
}
|
||||
|
||||
/// When we have a ty alias we *may* have two where clauses. To give the best diagnostics, we set the span
|
||||
@@ -51,17 +74,17 @@ fn add_ty_alias_where_clause(
|
||||
if before.0 || !after.0 { before } else { after };
|
||||
}
|
||||
|
||||
impl<'a, 'hir> ItemLowerer<'a, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> ItemLowerer<'_, 'hir, R> {
|
||||
fn with_lctx(
|
||||
&mut self,
|
||||
owner: NodeId,
|
||||
f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>,
|
||||
f: impl FnOnce(&mut LoweringContext<'_, 'hir, R>) -> hir::OwnerNode<'hir>,
|
||||
) {
|
||||
let mut lctx = LoweringContext::new(self.tcx, self.ast_index, self.resolver);
|
||||
let mut lctx = LoweringContext::new(self.tcx, self.resolver);
|
||||
lctx.with_hir_id_owner(owner, |lctx| f(lctx));
|
||||
|
||||
for (def_id, info) in lctx.children {
|
||||
let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
|
||||
let owner = self.owners.get_or_insert_mut(def_id);
|
||||
assert!(
|
||||
matches!(owner, hir::MaybeOwner::Phantom),
|
||||
"duplicate copy of {def_id:?} in lctx.children"
|
||||
@@ -71,13 +94,13 @@ fn with_lctx(
|
||||
}
|
||||
|
||||
pub(super) fn lower_node(&mut self, def_id: LocalDefId) {
|
||||
let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
|
||||
let owner = self.owners.get_or_insert_mut(def_id);
|
||||
if let hir::MaybeOwner::Phantom = owner {
|
||||
let node = self.ast_index[def_id];
|
||||
match node {
|
||||
AstOwner::NonOwner => {}
|
||||
AstOwner::Crate(c) => {
|
||||
assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID);
|
||||
assert_eq!(self.resolver.local_def_id(CRATE_NODE_ID), CRATE_DEF_ID);
|
||||
self.with_lctx(CRATE_NODE_ID, |lctx| {
|
||||
let module = lctx.lower_mod(&c.items, &c.spans);
|
||||
// FIXME(jdonszelman): is dummy span ever a problem here?
|
||||
@@ -99,7 +122,7 @@ pub(super) fn lower_node(&mut self, def_id: LocalDefId) {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
pub(super) fn lower_mod(
|
||||
&mut self,
|
||||
items: &[Box<Item>],
|
||||
@@ -345,6 +368,7 @@ fn lower_item_kind(
|
||||
body.as_deref(),
|
||||
attrs,
|
||||
contract.as_deref(),
|
||||
header.constness,
|
||||
);
|
||||
|
||||
let itctx = ImplTraitContext::Universal;
|
||||
@@ -1024,6 +1048,7 @@ fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
|
||||
Some(body),
|
||||
attrs,
|
||||
contract.as_deref(),
|
||||
sig.header.constness,
|
||||
);
|
||||
let (generics, sig) = self.lower_method_sig(
|
||||
generics,
|
||||
@@ -1217,6 +1242,7 @@ fn lower_impl_item(
|
||||
body.as_deref(),
|
||||
attrs,
|
||||
contract.as_deref(),
|
||||
sig.header.constness,
|
||||
);
|
||||
let (generics, sig) = self.lower_method_sig(
|
||||
generics,
|
||||
@@ -1346,11 +1372,13 @@ pub(super) fn lower_body(
|
||||
f: impl FnOnce(&mut Self) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>),
|
||||
) -> hir::BodyId {
|
||||
let prev_coroutine_kind = self.coroutine_kind.take();
|
||||
let prev_is_in_const_context = mem::take(&mut self.is_in_const_context);
|
||||
let task_context = self.task_context.take();
|
||||
let (parameters, result) = f(self);
|
||||
let body_id = self.record_body(parameters, result);
|
||||
self.task_context = task_context;
|
||||
self.coroutine_kind = prev_coroutine_kind;
|
||||
self.is_in_const_context = prev_is_in_const_context;
|
||||
body_id
|
||||
}
|
||||
|
||||
@@ -1369,9 +1397,13 @@ pub(super) fn lower_fn_body(
|
||||
&mut self,
|
||||
decl: &FnDecl,
|
||||
contract: Option<&FnContract>,
|
||||
constness: Const,
|
||||
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
|
||||
) -> hir::BodyId {
|
||||
self.lower_body(|this| {
|
||||
if let Const::Yes(_) = constness {
|
||||
this.is_in_const_context = true;
|
||||
}
|
||||
let params =
|
||||
this.arena.alloc_from_iter(decl.inputs.iter().map(|x| this.lower_param(x)));
|
||||
|
||||
@@ -1389,8 +1421,9 @@ fn lower_fn_body_block(
|
||||
decl: &FnDecl,
|
||||
body: &Block,
|
||||
contract: Option<&FnContract>,
|
||||
constness: Const,
|
||||
) -> hir::BodyId {
|
||||
self.lower_fn_body(decl, contract, |this| this.lower_block_expr(body))
|
||||
self.lower_fn_body(decl, contract, constness, |this| this.lower_block_expr(body))
|
||||
}
|
||||
|
||||
pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hir::BodyId {
|
||||
@@ -1398,7 +1431,10 @@ pub(super) fn lower_const_body(&mut self, span: Span, expr: Option<&Expr>) -> hi
|
||||
(
|
||||
&[],
|
||||
match expr {
|
||||
Some(expr) => this.lower_expr_mut(expr),
|
||||
Some(expr) => {
|
||||
this.is_in_const_context = true;
|
||||
this.lower_expr_mut(expr)
|
||||
}
|
||||
None => this.expr_err(span, this.dcx().span_delayed_bug(span, "no block")),
|
||||
},
|
||||
)
|
||||
@@ -1417,12 +1453,13 @@ fn lower_maybe_coroutine_body(
|
||||
body: Option<&Block>,
|
||||
attrs: &'hir [hir::Attribute],
|
||||
contract: Option<&FnContract>,
|
||||
constness: Const,
|
||||
) -> hir::BodyId {
|
||||
let Some(body) = body else {
|
||||
// Functions without a body are an error, except if this is an intrinsic. For those we
|
||||
// create a fake body so that the entire rest of the compiler doesn't have to deal with
|
||||
// this as a special case.
|
||||
return self.lower_fn_body(decl, contract, |this| {
|
||||
return self.lower_fn_body(decl, contract, constness, |this| {
|
||||
if find_attr!(attrs, RustcIntrinsic) || this.tcx.is_sdylib_interface_build() {
|
||||
let span = this.lower_span(span);
|
||||
let empty_block = hir::Block {
|
||||
@@ -1447,7 +1484,7 @@ fn lower_maybe_coroutine_body(
|
||||
};
|
||||
let Some(coroutine_kind) = coroutine_kind else {
|
||||
// Typical case: not a coroutine.
|
||||
return self.lower_fn_body_block(decl, body, contract);
|
||||
return self.lower_fn_body_block(decl, body, contract, constness);
|
||||
};
|
||||
// FIXME(contracts): Support contracts on async fn.
|
||||
self.lower_body(|this| {
|
||||
@@ -1475,7 +1512,7 @@ fn lower_maybe_coroutine_body(
|
||||
pub(crate) fn lower_coroutine_body_with_moved_arguments(
|
||||
&mut self,
|
||||
decl: &FnDecl,
|
||||
lower_body: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::Expr<'hir>,
|
||||
lower_body: impl FnOnce(&mut LoweringContext<'_, 'hir, R>) -> hir::Expr<'hir>,
|
||||
fn_decl_span: Span,
|
||||
body_span: Span,
|
||||
coroutine_kind: CoroutineKind,
|
||||
@@ -1612,7 +1649,7 @@ pub(crate) fn lower_coroutine_body_with_moved_arguments(
|
||||
parameters.push(new_parameter);
|
||||
}
|
||||
|
||||
let mkbody = |this: &mut LoweringContext<'_, 'hir>| {
|
||||
let mkbody = |this: &mut LoweringContext<'_, 'hir, R>| {
|
||||
// Create a block from the user's function body:
|
||||
let user_body = lower_body(this);
|
||||
|
||||
|
||||
@@ -42,9 +42,10 @@
|
||||
use rustc_ast::{self as ast, *};
|
||||
use rustc_attr_parsing::{AttributeParser, Late, OmitDoc};
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::sync::spawn;
|
||||
use rustc_data_structures::steal::Steal;
|
||||
use rustc_data_structures::tagged_ptr::TaggedRef;
|
||||
use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle};
|
||||
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
|
||||
@@ -57,8 +58,9 @@
|
||||
};
|
||||
use rustc_index::{Idx, IndexSlice, IndexVec};
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::hir::{self as mid_hir};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
|
||||
use rustc_middle::ty::{DelegationInfo, ResolverAstLowering, TyCtxt};
|
||||
use rustc_session::parse::add_feature_diagnostics;
|
||||
use rustc_span::symbol::{Ident, Symbol, kw, sym};
|
||||
use rustc_span::{DUMMY_SP, DesugaringKind, Span};
|
||||
@@ -67,6 +69,7 @@
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait};
|
||||
use crate::item::Owners;
|
||||
|
||||
macro_rules! arena_vec {
|
||||
($this:expr; $($x:expr),*) => (
|
||||
@@ -87,18 +90,9 @@ macro_rules! arena_vec {
|
||||
mod path;
|
||||
pub mod stability;
|
||||
|
||||
struct LoweringContext<'a, 'hir> {
|
||||
struct LoweringContext<'a, 'hir, R> {
|
||||
tcx: TyCtxt<'hir>,
|
||||
|
||||
// During lowering of delegation we need to access AST of other functions
|
||||
// in order to properly propagate generics, we could have done it at resolve
|
||||
// stage, however it will require either to firstly identify functions that
|
||||
// are being reused and store their generics, or to store generics of all functions
|
||||
// in resolver. This approach helps with those problems, as functions that are reused
|
||||
// will be in AST index.
|
||||
ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
|
||||
|
||||
resolver: &'a mut ResolverAstLowering<'hir>,
|
||||
resolver: &'a mut R,
|
||||
disambiguator: DisambiguatorState,
|
||||
|
||||
/// Used to allocate HIR nodes.
|
||||
@@ -129,6 +123,7 @@ struct LoweringContext<'a, 'hir> {
|
||||
loop_scope: Option<HirId>,
|
||||
is_in_loop_condition: bool,
|
||||
is_in_dyn_type: bool,
|
||||
is_in_const_context: bool,
|
||||
|
||||
current_hir_id_owner: hir::OwnerId,
|
||||
item_local_id_counter: hir::ItemLocalId,
|
||||
@@ -157,17 +152,11 @@ struct LoweringContext<'a, 'hir> {
|
||||
attribute_parser: AttributeParser<'hir>,
|
||||
}
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
fn new(
|
||||
tcx: TyCtxt<'hir>,
|
||||
ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
|
||||
resolver: &'a mut ResolverAstLowering<'hir>,
|
||||
) -> Self {
|
||||
impl<'a, 'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'a, 'hir, R> {
|
||||
fn new(tcx: TyCtxt<'hir>, resolver: &'a mut R) -> Self {
|
||||
let registered_tools = tcx.registered_tools(()).iter().map(|x| x.name).collect();
|
||||
Self {
|
||||
// Pseudo-globals.
|
||||
tcx,
|
||||
ast_index,
|
||||
resolver,
|
||||
disambiguator: DisambiguatorState::new(),
|
||||
arena: tcx.hir_arena,
|
||||
@@ -190,6 +179,7 @@ fn new(
|
||||
loop_scope: None,
|
||||
is_in_loop_condition: false,
|
||||
is_in_dyn_type: false,
|
||||
is_in_const_context: false,
|
||||
coroutine_kind: None,
|
||||
task_context: None,
|
||||
current_item: None,
|
||||
@@ -246,9 +236,84 @@ fn lower(&self, span: Span) -> Span {
|
||||
}
|
||||
}
|
||||
|
||||
#[extension(trait ResolverAstLoweringExt)]
|
||||
impl ResolverAstLowering<'_> {
|
||||
fn legacy_const_generic_args(&self, expr: &Expr, tcx: TyCtxt<'_>) -> Option<Vec<usize>> {
|
||||
struct ResolverDelayedAstLowering<'a, 'tcx> {
|
||||
node_id_to_def_id: NodeMap<LocalDefId>,
|
||||
partial_res_map: NodeMap<PartialRes>,
|
||||
next_node_id: NodeId,
|
||||
base: &'a ResolverAstLowering<'tcx>,
|
||||
}
|
||||
|
||||
// FIXME(fn_delegation): delegate this trait impl to `self.base`
|
||||
impl<'a, 'tcx> ResolverAstLoweringExt<'tcx> for ResolverDelayedAstLowering<'a, 'tcx> {
|
||||
fn legacy_const_generic_args(&self, expr: &Expr, tcx: TyCtxt<'tcx>) -> Option<Vec<usize>> {
|
||||
self.base.legacy_const_generic_args(expr, tcx)
|
||||
}
|
||||
|
||||
fn get_partial_res(&self, id: NodeId) -> Option<PartialRes> {
|
||||
self.partial_res_map.get(&id).copied().or_else(|| self.base.get_partial_res(id))
|
||||
}
|
||||
|
||||
fn get_import_res(&self, id: NodeId) -> PerNS<Option<Res<NodeId>>> {
|
||||
self.base.get_import_res(id)
|
||||
}
|
||||
|
||||
fn get_label_res(&self, id: NodeId) -> Option<NodeId> {
|
||||
self.base.get_label_res(id)
|
||||
}
|
||||
|
||||
fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes> {
|
||||
self.base.get_lifetime_res(id)
|
||||
}
|
||||
|
||||
fn extra_lifetime_params(&self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> {
|
||||
self.base.extra_lifetime_params(id)
|
||||
}
|
||||
|
||||
fn delegation_info(&self, id: LocalDefId) -> Option<&DelegationInfo> {
|
||||
self.base.delegation_info(id)
|
||||
}
|
||||
|
||||
fn opt_local_def_id(&self, id: NodeId) -> Option<LocalDefId> {
|
||||
self.node_id_to_def_id.get(&id).copied().or_else(|| self.base.opt_local_def_id(id))
|
||||
}
|
||||
|
||||
fn local_def_id(&self, id: NodeId) -> LocalDefId {
|
||||
self.opt_local_def_id(id).expect("must have def_id")
|
||||
}
|
||||
|
||||
fn lifetime_elision_allowed(&self, id: NodeId) -> bool {
|
||||
self.base.lifetime_elision_allowed(id)
|
||||
}
|
||||
|
||||
fn insert_new_def_id(&mut self, node_id: NodeId, def_id: LocalDefId) {
|
||||
self.node_id_to_def_id.insert(node_id, def_id);
|
||||
}
|
||||
|
||||
fn insert_partial_res(&mut self, node_id: NodeId, res: PartialRes) {
|
||||
self.partial_res_map.insert(node_id, res);
|
||||
}
|
||||
|
||||
fn trait_candidates(&self, node_id: NodeId) -> Option<&'tcx [hir::TraitCandidate<'tcx>]> {
|
||||
self.base.trait_candidates(node_id)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn next_node_id(&mut self) -> NodeId {
|
||||
next_node_id(&mut self.next_node_id)
|
||||
}
|
||||
}
|
||||
|
||||
fn next_node_id(current_id: &mut NodeId) -> NodeId {
|
||||
let start = *current_id;
|
||||
let next = start.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
|
||||
*current_id = ast::NodeId::from_u32(next);
|
||||
|
||||
start
|
||||
}
|
||||
|
||||
#[extension(trait ResolverAstLoweringExt<'tcx>)]
|
||||
impl<'tcx> ResolverAstLowering<'tcx> {
|
||||
fn legacy_const_generic_args(&self, expr: &Expr, tcx: TyCtxt<'tcx>) -> Option<Vec<usize>> {
|
||||
let ExprKind::Path(None, path) = &expr.kind else {
|
||||
return None;
|
||||
};
|
||||
@@ -259,7 +324,7 @@ fn legacy_const_generic_args(&self, expr: &Expr, tcx: TyCtxt<'_>) -> Option<Vec<
|
||||
return None;
|
||||
}
|
||||
|
||||
let def_id = self.partial_res_map.get(&expr.id)?.full_res()?.opt_def_id()?;
|
||||
let def_id = self.get_partial_res(expr.id)?.full_res()?.opt_def_id()?;
|
||||
|
||||
// We only support cross-crate argument rewriting. Uses
|
||||
// within the same crate should be updated to use the new
|
||||
@@ -302,9 +367,42 @@ fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes> {
|
||||
///
|
||||
/// The extra lifetimes that appear from the parenthesized `Fn`-trait desugaring
|
||||
/// should appear at the enclosing `PolyTraitRef`.
|
||||
fn extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> {
|
||||
fn extra_lifetime_params(&self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> {
|
||||
self.extra_lifetime_params_map.get(&id).cloned().unwrap_or_default()
|
||||
}
|
||||
|
||||
fn delegation_info(&self, id: LocalDefId) -> Option<&DelegationInfo> {
|
||||
self.delegation_infos.get(&id)
|
||||
}
|
||||
|
||||
fn opt_local_def_id(&self, id: NodeId) -> Option<LocalDefId> {
|
||||
self.node_id_to_def_id.get(&id).copied()
|
||||
}
|
||||
|
||||
fn local_def_id(&self, id: NodeId) -> LocalDefId {
|
||||
self.opt_local_def_id(id).expect("must have def_id")
|
||||
}
|
||||
|
||||
fn lifetime_elision_allowed(&self, id: NodeId) -> bool {
|
||||
self.lifetime_elision_allowed.contains(&id)
|
||||
}
|
||||
|
||||
fn insert_new_def_id(&mut self, node_id: NodeId, def_id: LocalDefId) {
|
||||
self.node_id_to_def_id.insert(node_id, def_id);
|
||||
}
|
||||
|
||||
fn insert_partial_res(&mut self, node_id: NodeId, res: PartialRes) {
|
||||
self.partial_res_map.insert(node_id, res);
|
||||
}
|
||||
|
||||
fn trait_candidates(&self, node_id: NodeId) -> Option<&'tcx [hir::TraitCandidate<'tcx>]> {
|
||||
self.trait_map.get(&node_id).copied()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn next_node_id(&mut self) -> NodeId {
|
||||
next_node_id(&mut self.next_node_id)
|
||||
}
|
||||
}
|
||||
|
||||
/// How relaxed bounds `?Trait` should be treated.
|
||||
@@ -444,42 +542,43 @@ enum TryBlockScope {
|
||||
Heterogeneous(HirId),
|
||||
}
|
||||
|
||||
fn index_crate<'a>(
|
||||
node_id_to_def_id: &NodeMap<LocalDefId>,
|
||||
fn index_crate<'a, 'b>(
|
||||
resolver: &'b impl ResolverAstLoweringExt<'a>,
|
||||
krate: &'a Crate,
|
||||
) -> IndexVec<LocalDefId, AstOwner<'a>> {
|
||||
let mut indexer = Indexer { node_id_to_def_id, index: IndexVec::new() };
|
||||
let mut indexer = Indexer { resolver, index: IndexVec::new() };
|
||||
*indexer.index.ensure_contains_elem(CRATE_DEF_ID, || AstOwner::NonOwner) =
|
||||
AstOwner::Crate(krate);
|
||||
visit::walk_crate(&mut indexer, krate);
|
||||
|
||||
return indexer.index;
|
||||
|
||||
struct Indexer<'s, 'a> {
|
||||
node_id_to_def_id: &'s NodeMap<LocalDefId>,
|
||||
struct Indexer<'a, 'b, R> {
|
||||
resolver: &'b R,
|
||||
index: IndexVec<LocalDefId, AstOwner<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> visit::Visitor<'a> for Indexer<'_, 'a> {
|
||||
impl<'a, 'b, R: ResolverAstLoweringExt<'a>> visit::Visitor<'a> for Indexer<'a, 'b, R> {
|
||||
fn visit_attribute(&mut self, _: &'a Attribute) {
|
||||
// We do not want to lower expressions that appear in attributes,
|
||||
// as they are not accessible to the rest of the HIR.
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, item: &'a ast::Item) {
|
||||
let def_id = self.node_id_to_def_id[&item.id];
|
||||
let def_id = self.resolver.local_def_id(item.id);
|
||||
*self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) = AstOwner::Item(item);
|
||||
visit::walk_item(self, item)
|
||||
}
|
||||
|
||||
fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: visit::AssocCtxt) {
|
||||
let def_id = self.node_id_to_def_id[&item.id];
|
||||
let def_id = self.resolver.local_def_id(item.id);
|
||||
*self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) =
|
||||
AstOwner::AssocItem(item, ctxt);
|
||||
visit::walk_assoc_item(self, item, ctxt);
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, item: &'a ast::ForeignItem) {
|
||||
let def_id = self.node_id_to_def_id[&item.id];
|
||||
let def_id = self.resolver.local_def_id(item.id);
|
||||
*self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) =
|
||||
AstOwner::ForeignItem(item);
|
||||
visit::walk_item(self, item);
|
||||
@@ -510,8 +609,7 @@ fn compute_hir_hash(
|
||||
})
|
||||
}
|
||||
|
||||
pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
|
||||
let sess = tcx.sess;
|
||||
pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> mid_hir::Crate<'_> {
|
||||
// Queries that borrow `resolver_for_lowering`.
|
||||
tcx.ensure_done().output_filenames(());
|
||||
tcx.ensure_done().early_lint_checks(());
|
||||
@@ -519,7 +617,7 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
|
||||
tcx.ensure_done().get_lang_items(());
|
||||
let (mut resolver, krate) = tcx.resolver_for_lowering().steal();
|
||||
|
||||
let ast_index = index_crate(&resolver.node_id_to_def_id, &krate);
|
||||
let ast_index = index_crate(&resolver, &krate);
|
||||
let mut owners = IndexVec::from_fn_n(
|
||||
|_| hir::MaybeOwner::Phantom,
|
||||
tcx.definitions_untracked().def_index_count(),
|
||||
@@ -529,25 +627,60 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
|
||||
tcx,
|
||||
resolver: &mut resolver,
|
||||
ast_index: &ast_index,
|
||||
owners: &mut owners,
|
||||
owners: Owners::IndexVec(&mut owners),
|
||||
};
|
||||
|
||||
let mut delayed_ids: FxIndexSet<LocalDefId> = Default::default();
|
||||
|
||||
for def_id in ast_index.indices() {
|
||||
lowerer.lower_node(def_id);
|
||||
match &ast_index[def_id] {
|
||||
AstOwner::Item(Item { kind: ItemKind::Delegation { .. }, .. })
|
||||
| AstOwner::AssocItem(Item { kind: AssocItemKind::Delegation { .. }, .. }, _) => {
|
||||
delayed_ids.insert(def_id);
|
||||
}
|
||||
_ => lowerer.lower_node(def_id),
|
||||
};
|
||||
}
|
||||
|
||||
drop(ast_index);
|
||||
|
||||
// Drop AST to free memory. It can be expensive so try to drop it on a separate thread.
|
||||
let prof = sess.prof.clone();
|
||||
spawn(move || {
|
||||
let _timer = prof.verbose_generic_activity("drop_ast");
|
||||
drop(krate);
|
||||
});
|
||||
|
||||
// Don't hash unless necessary, because it's expensive.
|
||||
let opt_hir_hash =
|
||||
if tcx.needs_crate_hash() { Some(compute_hir_hash(tcx, &owners)) } else { None };
|
||||
hir::Crate { owners, opt_hir_hash }
|
||||
|
||||
let delayed_resolver = Steal::new((resolver, krate));
|
||||
mid_hir::Crate::new(owners, delayed_ids, delayed_resolver, opt_hir_hash)
|
||||
}
|
||||
|
||||
/// Lowers an AST owner corresponding to `def_id`, now only delegations are lowered this way.
|
||||
pub fn lower_delayed_owner(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
let krate = tcx.hir_crate(());
|
||||
|
||||
let (resolver, krate) = &*krate.delayed_resolver.borrow();
|
||||
|
||||
// FIXME!!!(fn_delegation): make ast index lifetime same as resolver,
|
||||
// as it is too bad to reindex whole crate on each delegation lowering.
|
||||
let ast_index = index_crate(resolver, krate);
|
||||
|
||||
let mut resolver = ResolverDelayedAstLowering {
|
||||
next_node_id: resolver.next_node_id,
|
||||
partial_res_map: Default::default(),
|
||||
node_id_to_def_id: Default::default(),
|
||||
base: resolver,
|
||||
};
|
||||
|
||||
let mut map = Default::default();
|
||||
|
||||
let mut lowerer = item::ItemLowerer {
|
||||
tcx,
|
||||
resolver: &mut resolver,
|
||||
ast_index: &ast_index,
|
||||
owners: Owners::Map(&mut map),
|
||||
};
|
||||
|
||||
lowerer.lower_node(def_id);
|
||||
|
||||
for (child_def_id, owner) in map {
|
||||
tcx.feed_delayed_owner(child_def_id, owner);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
@@ -577,7 +710,7 @@ enum GenericArgsMode {
|
||||
Silence,
|
||||
}
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
fn create_def(
|
||||
&mut self,
|
||||
node_id: ast::NodeId,
|
||||
@@ -603,22 +736,19 @@ fn create_def(
|
||||
.def_id();
|
||||
|
||||
debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id);
|
||||
self.resolver.node_id_to_def_id.insert(node_id, def_id);
|
||||
self.resolver.insert_new_def_id(node_id, def_id);
|
||||
|
||||
def_id
|
||||
}
|
||||
|
||||
fn next_node_id(&mut self) -> NodeId {
|
||||
let start = self.resolver.next_node_id;
|
||||
let next = start.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
|
||||
self.resolver.next_node_id = ast::NodeId::from_u32(next);
|
||||
start
|
||||
self.resolver.next_node_id()
|
||||
}
|
||||
|
||||
/// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name
|
||||
/// resolver (if any).
|
||||
fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
|
||||
self.resolver.node_id_to_def_id.get(&node).copied()
|
||||
self.resolver.opt_local_def_id(node)
|
||||
}
|
||||
|
||||
fn local_def_id(&self, node: NodeId) -> LocalDefId {
|
||||
@@ -747,7 +877,7 @@ fn lower_node_id(&mut self, ast_node_id: NodeId) -> HirId {
|
||||
self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id)));
|
||||
}
|
||||
|
||||
if let Some(&traits) = self.resolver.trait_map.get(&ast_node_id) {
|
||||
if let Some(traits) = self.resolver.trait_candidates(ast_node_id) {
|
||||
self.trait_map.insert(hir_id.local_id, traits);
|
||||
}
|
||||
|
||||
@@ -1135,7 +1265,7 @@ fn lower_assoc_item_constraint(
|
||||
};
|
||||
gen_args_ctor.into_generic_args(self)
|
||||
} else {
|
||||
self.arena.alloc(hir::GenericArgs::none())
|
||||
hir::GenericArgs::NONE
|
||||
};
|
||||
let kind = match &constraint.kind {
|
||||
AssocItemConstraintKind::Equality { term } => {
|
||||
@@ -1267,9 +1397,13 @@ fn lower_generic_arg(
|
||||
}
|
||||
GenericArg::Type(self.lower_ty_alloc(ty, itctx).try_as_ambig_ty().unwrap())
|
||||
}
|
||||
ast::GenericArg::Const(ct) => GenericArg::Const(
|
||||
self.lower_anon_const_to_const_arg_and_alloc(ct).try_as_ambig_ct().unwrap(),
|
||||
),
|
||||
ast::GenericArg::Const(ct) => {
|
||||
let ct = self.lower_anon_const_to_const_arg_and_alloc(ct);
|
||||
match ct.try_as_ambig_ct() {
|
||||
Some(ct) => GenericArg::Const(ct),
|
||||
None => GenericArg::Infer(hir::InferArg { hir_id: ct.hir_id, span: ct.span }),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1764,7 +1898,7 @@ fn lower_fn_decl(
|
||||
inputs,
|
||||
output,
|
||||
c_variadic,
|
||||
lifetime_elision_allowed: self.resolver.lifetime_elision_allowed.contains(&fn_node_id),
|
||||
lifetime_elision_allowed: self.resolver.lifetime_elision_allowed(fn_node_id),
|
||||
implicit_self: decl.inputs.get(0).map_or(hir::ImplicitSelfKind::None, |arg| {
|
||||
let is_mutable_pat = matches!(
|
||||
arg.pat.kind,
|
||||
@@ -2951,7 +3085,10 @@ fn is_empty(&self) -> bool {
|
||||
&& self.parenthesized == hir::GenericArgsParentheses::No
|
||||
}
|
||||
|
||||
fn into_generic_args(self, this: &LoweringContext<'_, 'hir>) -> &'hir hir::GenericArgs<'hir> {
|
||||
fn into_generic_args(
|
||||
self,
|
||||
this: &LoweringContext<'_, 'hir, impl ResolverAstLoweringExt<'hir>>,
|
||||
) -> &'hir hir::GenericArgs<'hir> {
|
||||
let ga = hir::GenericArgs {
|
||||
args: this.arena.alloc_from_iter(self.args),
|
||||
constraints: self.constraints,
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
use rustc_hir::definitions::DefPathData;
|
||||
use rustc_hir::{self as hir, LangItem, Target};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_span::source_map::{Spanned, respan};
|
||||
use rustc_span::{DesugaringKind, Ident, Span};
|
||||
use rustc_span::{DesugaringKind, Ident, Span, Spanned, respan};
|
||||
|
||||
use super::errors::{
|
||||
ArbitraryExpressionInPattern, ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding,
|
||||
@@ -15,7 +14,7 @@
|
||||
use super::{ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt};
|
||||
use crate::{AllowReturnTypeNotation, ImplTraitPosition};
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
pub(crate) fn lower_pat(&mut self, pattern: &Pat) -> &'hir hir::Pat<'hir> {
|
||||
self.arena.alloc(self.lower_pat_mut(pattern))
|
||||
}
|
||||
@@ -134,8 +133,11 @@ fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> {
|
||||
self.lower_range_end(end, e2.is_some()),
|
||||
);
|
||||
}
|
||||
PatKind::Guard(inner, cond) => {
|
||||
break hir::PatKind::Guard(self.lower_pat(inner), self.lower_expr(cond));
|
||||
PatKind::Guard(inner, guard) => {
|
||||
break hir::PatKind::Guard(
|
||||
self.lower_pat(inner),
|
||||
self.lower_expr(&guard.cond),
|
||||
);
|
||||
}
|
||||
PatKind::Slice(pats) => break self.lower_pat_slice(pats),
|
||||
PatKind::Rest => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use rustc_ast::{self as ast, *};
|
||||
use rustc_errors::StashKey;
|
||||
use rustc_hir::def::{DefKind, PartialRes, PerNS, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{self as hir, GenericArg};
|
||||
@@ -19,7 +20,7 @@
|
||||
LifetimeRes, LoweringContext, ParamMode, ResolverAstLoweringExt,
|
||||
};
|
||||
|
||||
impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
pub(crate) fn lower_qpath(
|
||||
&mut self,
|
||||
@@ -298,7 +299,7 @@ pub(crate) fn lower_path_segment(
|
||||
sym::return_type_notation,
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
err.stash(path_span, StashKey::ReturnTypeNotation);
|
||||
(
|
||||
GenericArgsCtor {
|
||||
args: Default::default(),
|
||||
|
||||
@@ -27,10 +27,9 @@
|
||||
use rustc_ast_pretty::pprust::{self, State};
|
||||
use rustc_attr_parsing::validate_attr;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_errors::{DiagCtxtHandle, LintBuffer};
|
||||
use rustc_errors::{DiagCtxtHandle, Diagnostic, LintBuffer};
|
||||
use rustc_feature::Features;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::lint::BuiltinLintDiag;
|
||||
use rustc_session::lint::builtin::{
|
||||
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN,
|
||||
PATTERNS_IN_FNS_WITHOUT_BODY, UNUSED_VISIBILITIES,
|
||||
@@ -1371,11 +1370,16 @@ fn visit_item(&mut self, item: &'a Item) {
|
||||
ItemKind::Struct(ident, generics, vdata) => {
|
||||
self.with_tilde_const(Some(TildeConstReason::Struct { span: item.span }), |this| {
|
||||
// Scalable vectors can only be tuple structs
|
||||
let is_scalable_vector =
|
||||
item.attrs.iter().any(|attr| attr.has_name(sym::rustc_scalable_vector));
|
||||
if is_scalable_vector && !matches!(vdata, VariantData::Tuple(..)) {
|
||||
this.dcx()
|
||||
.emit_err(errors::ScalableVectorNotTupleStruct { span: item.span });
|
||||
let scalable_vector_attr =
|
||||
item.attrs.iter().find(|attr| attr.has_name(sym::rustc_scalable_vector));
|
||||
if let Some(attr) = scalable_vector_attr {
|
||||
if !matches!(vdata, VariantData::Tuple(..)) {
|
||||
this.dcx()
|
||||
.emit_err(errors::ScalableVectorNotTupleStruct { span: item.span });
|
||||
}
|
||||
if !self.sess.target.arch.supports_scalable_vectors() {
|
||||
this.dcx().emit_err(errors::ScalableVectorBadArch { span: attr.span });
|
||||
}
|
||||
}
|
||||
|
||||
match vdata {
|
||||
@@ -1419,7 +1423,7 @@ fn visit_item(&mut self, item: &'a Item) {
|
||||
UNUSED_VISIBILITIES,
|
||||
item.id,
|
||||
item.vis.span,
|
||||
BuiltinLintDiag::UnusedVisibility(item.vis.span),
|
||||
errors::UnusedVisibility { span: item.vis.span },
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1482,6 +1486,15 @@ fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
|
||||
ident,
|
||||
sig,
|
||||
);
|
||||
|
||||
if let Some(attr) = attr::find_by_name(fi.attrs(), sym::track_caller)
|
||||
&& self.extern_mod_abi != Some(ExternAbi::Rust)
|
||||
{
|
||||
self.dcx().emit_err(errors::RequiresRustAbi {
|
||||
track_caller_span: attr.span,
|
||||
extern_abi_span: self.current_extern_span(),
|
||||
});
|
||||
}
|
||||
}
|
||||
ForeignItemKind::TyAlias(box TyAlias {
|
||||
defaultness,
|
||||
@@ -1667,10 +1680,19 @@ fn visit_fn(&mut self, fk: FnKind<'a>, attrs: &AttrVec, span: Span, id: NodeId)
|
||||
}
|
||||
|
||||
if let FnKind::Fn(ctxt, _, fun) = fk
|
||||
&& let Extern::Explicit(str_lit, _) = fun.sig.header.ext
|
||||
&& let Extern::Explicit(str_lit, extern_abi_span) = fun.sig.header.ext
|
||||
&& let Ok(abi) = ExternAbi::from_str(str_lit.symbol.as_str())
|
||||
{
|
||||
self.check_extern_fn_signature(abi, ctxt, &fun.ident, &fun.sig);
|
||||
|
||||
if let Some(attr) = attr::find_by_name(attrs, sym::track_caller)
|
||||
&& abi != ExternAbi::Rust
|
||||
{
|
||||
self.dcx().emit_err(errors::RequiresRustAbi {
|
||||
track_caller_span: attr.span,
|
||||
extern_abi_span,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
self.check_c_variadic_type(fk, attrs);
|
||||
@@ -1708,14 +1730,19 @@ fn visit_fn(&mut self, fk: FnKind<'a>, attrs: &AttrVec, span: Span, id: NodeId)
|
||||
Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
|
||||
if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
|
||||
if let Some(ident) = ident {
|
||||
self.lint_buffer.buffer_lint(
|
||||
let is_foreign = matches!(ctxt, FnCtxt::Foreign);
|
||||
self.lint_buffer.dyn_buffer_lint(
|
||||
PATTERNS_IN_FNS_WITHOUT_BODY,
|
||||
id,
|
||||
span,
|
||||
BuiltinLintDiag::PatternsInFnsWithoutBody {
|
||||
span,
|
||||
ident,
|
||||
is_foreign: matches!(ctxt, FnCtxt::Foreign),
|
||||
move |dcx, level| {
|
||||
let sub = errors::PatternsInFnsWithoutBodySub { ident, span };
|
||||
if is_foreign {
|
||||
errors::PatternsInFnsWithoutBody::Foreign { sub }
|
||||
} else {
|
||||
errors::PatternsInFnsWithoutBody::Bodiless { sub }
|
||||
}
|
||||
.into_diag(dcx, level)
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -1805,11 +1832,26 @@ fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
|
||||
Some((right, snippet))
|
||||
}
|
||||
};
|
||||
self.lint_buffer.buffer_lint(
|
||||
let left_sp = err.span;
|
||||
self.lint_buffer.dyn_buffer_lint(
|
||||
DEPRECATED_WHERE_CLAUSE_LOCATION,
|
||||
item.id,
|
||||
err.span,
|
||||
BuiltinLintDiag::DeprecatedWhereclauseLocation(err.span, sugg),
|
||||
move |dcx, level| {
|
||||
let suggestion = match sugg {
|
||||
Some((right_sp, sugg)) => {
|
||||
errors::DeprecatedWhereClauseLocationSugg::MoveToEnd {
|
||||
left: left_sp,
|
||||
right: right_sp,
|
||||
sugg,
|
||||
}
|
||||
}
|
||||
None => {
|
||||
errors::DeprecatedWhereClauseLocationSugg::RemoveWhere { span: left_sp }
|
||||
}
|
||||
};
|
||||
errors::DeprecatedWhereClauseLocation { suggestion }.into_diag(dcx, level)
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1133,3 +1133,89 @@ pub(crate) struct ScalableVectorNotTupleStruct {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("scalable vectors are not supported on this architecture")]
|
||||
pub(crate) struct ScalableVectorBadArch {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`#[track_caller]` can only be used with the Rust ABI", code = E0737)]
|
||||
pub(crate) struct RequiresRustAbi {
|
||||
#[primary_span]
|
||||
#[label("using `#[track_caller]` here")]
|
||||
pub track_caller_span: Span,
|
||||
#[label("not using the Rust ABI because of this")]
|
||||
pub extern_abi_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("visibility qualifiers have no effect on `const _` declarations")]
|
||||
#[note("`const _` does not declare a name, so there is nothing for the qualifier to apply to")]
|
||||
pub(crate) struct UnusedVisibility {
|
||||
#[suggestion(
|
||||
"remove the qualifier",
|
||||
style = "short",
|
||||
code = "",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(
|
||||
"remove `mut` from the parameter",
|
||||
code = "{ident}",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub(crate) struct PatternsInFnsWithoutBodySub {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
||||
pub ident: Ident,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
pub(crate) enum PatternsInFnsWithoutBody {
|
||||
#[diag("patterns aren't allowed in foreign function declarations")]
|
||||
Foreign {
|
||||
#[subdiagnostic]
|
||||
sub: PatternsInFnsWithoutBodySub,
|
||||
},
|
||||
#[diag("patterns aren't allowed in functions without bodies")]
|
||||
Bodiless {
|
||||
#[subdiagnostic]
|
||||
sub: PatternsInFnsWithoutBodySub,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("where clause not allowed here")]
|
||||
#[note("see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information")]
|
||||
pub(crate) struct DeprecatedWhereClauseLocation {
|
||||
#[subdiagnostic]
|
||||
pub suggestion: DeprecatedWhereClauseLocationSugg,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum DeprecatedWhereClauseLocationSugg {
|
||||
#[multipart_suggestion(
|
||||
"move it to the end of the type declaration",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
MoveToEnd {
|
||||
#[suggestion_part(code = "")]
|
||||
left: Span,
|
||||
#[suggestion_part(code = "{sugg}")]
|
||||
right: Span,
|
||||
|
||||
sugg: String,
|
||||
},
|
||||
#[suggestion("remove this `where`", code = "", applicability = "machine-applicable")]
|
||||
RemoveWhere {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
|
||||
use rustc_ast::{self as ast, AttrVec, NodeId, PatKind, attr, token};
|
||||
use rustc_ast::{self as ast, AttrVec, GenericBound, NodeId, PatKind, attr, token};
|
||||
use rustc_attr_parsing::AttributeParser;
|
||||
use rustc_errors::msg;
|
||||
use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Features};
|
||||
@@ -7,8 +7,7 @@
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::parse::{feature_err, feature_warn};
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
|
||||
use rustc_span::{DUMMY_SP, Span, Spanned, Symbol, sym};
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
use crate::errors;
|
||||
@@ -150,7 +149,14 @@ fn check_late_bound_lifetime_defs(&self, params: &[ast::GenericParam]) {
|
||||
for param in params {
|
||||
if !param.bounds.is_empty() {
|
||||
let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
|
||||
self.sess.dcx().emit_err(errors::ForbiddenBound { spans });
|
||||
if param.bounds.iter().any(|bound| matches!(bound, GenericBound::Trait(_))) {
|
||||
// Issue #149695
|
||||
// Abort immediately otherwise items defined in complex bounds will be lowered into HIR,
|
||||
// which will cause ICEs when errors of the items visit unlowered parents.
|
||||
self.sess.dcx().emit_fatal(errors::ForbiddenBound { spans });
|
||||
} else {
|
||||
self.sess.dcx().emit_err(errors::ForbiddenBound { spans });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,9 +20,11 @@
|
||||
RangeEnd, RangeSyntax, Safety, SelfKind, Term, attr,
|
||||
};
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::source_map::{SourceMap, Spanned};
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::symbol::IdentPrinter;
|
||||
use rustc_span::{BytePos, CharPos, DUMMY_SP, FileName, Ident, Pos, Span, Symbol, kw, sym};
|
||||
use rustc_span::{
|
||||
BytePos, CharPos, DUMMY_SP, FileName, Ident, Pos, Span, Spanned, Symbol, kw, sym,
|
||||
};
|
||||
|
||||
use crate::pp::Breaks::{Consistent, Inconsistent};
|
||||
use crate::pp::{self, BoxMarker, Breaks};
|
||||
@@ -327,6 +329,19 @@ fn print_crate_inner<'a>(
|
||||
/// - #63896: `#[allow(unused,` must be printed rather than `#[allow(unused ,`
|
||||
/// - #73345: `#[allow(unused)]` must be printed rather than `# [allow(unused)]`
|
||||
///
|
||||
/// Returns `true` if both token trees are identifier-like tokens that would
|
||||
/// merge into a single token if printed without a space between them.
|
||||
/// E.g. `ident` + `where` would merge into `identwhere`.
|
||||
fn idents_would_merge(tt1: &TokenTree, tt2: &TokenTree) -> bool {
|
||||
fn is_ident_like(tt: &TokenTree) -> bool {
|
||||
matches!(
|
||||
tt,
|
||||
TokenTree::Token(Token { kind: token::Ident(..) | token::NtIdent(..), .. }, _,)
|
||||
)
|
||||
}
|
||||
is_ident_like(tt1) && is_ident_like(tt2)
|
||||
}
|
||||
|
||||
fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool {
|
||||
use Delimiter::*;
|
||||
use TokenTree::{Delimited as Del, Token as Tok};
|
||||
@@ -735,6 +750,23 @@ fn print_tt(&mut self, tt: &TokenTree, convert_dollar_crate: bool) -> Spacing {
|
||||
TokenTree::Token(token, spacing) => {
|
||||
let token_str = self.token_to_string_ext(token, convert_dollar_crate);
|
||||
self.word(token_str);
|
||||
// Emit hygiene annotations for identity-bearing tokens,
|
||||
// matching how print_ident() and print_lifetime() call ann_post().
|
||||
match token.kind {
|
||||
token::Ident(name, _) => {
|
||||
self.ann_post(Ident::new(name, token.span));
|
||||
}
|
||||
token::NtIdent(ident, _) => {
|
||||
self.ann_post(ident);
|
||||
}
|
||||
token::Lifetime(name, _) => {
|
||||
self.ann_post(Ident::new(name, token.span));
|
||||
}
|
||||
token::NtLifetime(ident, _) => {
|
||||
self.ann_post(ident);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if let token::DocComment(..) = token.kind {
|
||||
self.hardbreak()
|
||||
}
|
||||
@@ -792,6 +824,13 @@ fn print_tts(&mut self, tts: &TokenStream, convert_dollar_crate: bool) {
|
||||
if let Some(next) = iter.peek() {
|
||||
if spacing == Spacing::Alone && space_between(tt, next) {
|
||||
self.space();
|
||||
} else if spacing != Spacing::Alone && idents_would_merge(tt, next) {
|
||||
// When tokens from macro `tt` captures preserve their
|
||||
// original `Joint`/`JointHidden` spacing, adjacent
|
||||
// identifier-like tokens can be concatenated without a
|
||||
// space (e.g. `$x:identwhere`). Insert a space to
|
||||
// prevent this.
|
||||
self.space();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1610,6 +1649,85 @@ fn print_mac(&mut self, m: &ast::MacCall) {
|
||||
);
|
||||
}
|
||||
|
||||
fn inline_asm_template_and_operands<'asm>(
|
||||
asm: &'asm ast::InlineAsm,
|
||||
) -> (String, Vec<&'asm InlineAsmOperand>) {
|
||||
fn is_explicit_reg(op: &InlineAsmOperand) -> bool {
|
||||
match op {
|
||||
InlineAsmOperand::In { reg, .. }
|
||||
| InlineAsmOperand::Out { reg, .. }
|
||||
| InlineAsmOperand::InOut { reg, .. }
|
||||
| InlineAsmOperand::SplitInOut { reg, .. } => {
|
||||
matches!(reg, InlineAsmRegOrRegClass::Reg(_))
|
||||
}
|
||||
InlineAsmOperand::Const { .. }
|
||||
| InlineAsmOperand::Sym { .. }
|
||||
| InlineAsmOperand::Label { .. } => false,
|
||||
}
|
||||
}
|
||||
|
||||
// After macro expansion, named operands become positional. The grammar
|
||||
// requires positional operands to precede explicit register operands,
|
||||
// so we must reorder when any non-explicit operand follows an explicit
|
||||
// one. When no reordering is needed, we use the original template
|
||||
// string and operand order to avoid duplicating the Display logic in
|
||||
// InlineAsmTemplatePiece.
|
||||
let needs_reorder = {
|
||||
let mut seen_explicit = false;
|
||||
asm.operands.iter().any(|(op, _)| {
|
||||
if is_explicit_reg(op) {
|
||||
seen_explicit = true;
|
||||
false
|
||||
} else {
|
||||
seen_explicit
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
if !needs_reorder {
|
||||
let template = InlineAsmTemplatePiece::to_string(&asm.template);
|
||||
let operands = asm.operands.iter().map(|(op, _)| op).collect();
|
||||
return (template, operands);
|
||||
}
|
||||
|
||||
let mut non_explicit = Vec::new();
|
||||
let mut explicit = Vec::new();
|
||||
for (i, (op, _)) in asm.operands.iter().enumerate() {
|
||||
if is_explicit_reg(op) {
|
||||
explicit.push(i);
|
||||
} else {
|
||||
non_explicit.push(i);
|
||||
}
|
||||
}
|
||||
let order = non_explicit.into_iter().chain(explicit).collect::<Vec<_>>();
|
||||
|
||||
// Build old-index -> new-index mapping for template renumbering.
|
||||
let mut old_to_new = vec![0usize; asm.operands.len()];
|
||||
for (new_idx, old_idx) in order.iter().copied().enumerate() {
|
||||
old_to_new[old_idx] = new_idx;
|
||||
}
|
||||
|
||||
// Remap template placeholder indices and reuse the existing Display
|
||||
// impl to build the template string.
|
||||
let remapped = asm
|
||||
.template
|
||||
.iter()
|
||||
.map(|piece| match piece {
|
||||
InlineAsmTemplatePiece::Placeholder { operand_idx, modifier, span } => {
|
||||
InlineAsmTemplatePiece::Placeholder {
|
||||
operand_idx: old_to_new[*operand_idx],
|
||||
modifier: *modifier,
|
||||
span: *span,
|
||||
}
|
||||
}
|
||||
other => other.clone(),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let template = InlineAsmTemplatePiece::to_string(&remapped);
|
||||
let operands = order.iter().map(|&idx| &asm.operands[idx].0).collect();
|
||||
(template, operands)
|
||||
}
|
||||
|
||||
fn print_inline_asm(&mut self, asm: &ast::InlineAsm) {
|
||||
enum AsmArg<'a> {
|
||||
Template(String),
|
||||
@@ -1618,8 +1736,9 @@ enum AsmArg<'a> {
|
||||
Options(InlineAsmOptions),
|
||||
}
|
||||
|
||||
let mut args = vec![AsmArg::Template(InlineAsmTemplatePiece::to_string(&asm.template))];
|
||||
args.extend(asm.operands.iter().map(|(o, _)| AsmArg::Operand(o)));
|
||||
let (template, operands) = Self::inline_asm_template_and_operands(asm);
|
||||
let mut args = vec![AsmArg::Template(template)];
|
||||
args.extend(operands.into_iter().map(AsmArg::Operand));
|
||||
for (abi, _) in &asm.clobber_abis {
|
||||
args.push(AsmArg::ClobberAbi(*abi));
|
||||
}
|
||||
@@ -1747,6 +1866,23 @@ fn print_qpath(&mut self, path: &ast::Path, qself: &ast::QSelf, colons_before_pa
|
||||
}
|
||||
}
|
||||
|
||||
/// Print a pattern, parenthesizing it if it is an or-pattern (`A | B`).
|
||||
///
|
||||
/// Or-patterns have the lowest precedence among patterns, so they need
|
||||
/// parentheses when nested inside `@` bindings, `&` references, or `box`
|
||||
/// patterns — otherwise `x @ A | B` parses as `(x @ A) | B`, `&A | B`
|
||||
/// parses as `(&A) | B`, etc.
|
||||
fn print_pat_paren_if_or(&mut self, pat: &ast::Pat) {
|
||||
let needs_paren = matches!(pat.kind, PatKind::Or(..));
|
||||
if needs_paren {
|
||||
self.popen();
|
||||
}
|
||||
self.print_pat(pat);
|
||||
if needs_paren {
|
||||
self.pclose();
|
||||
}
|
||||
}
|
||||
|
||||
fn print_pat(&mut self, pat: &ast::Pat) {
|
||||
self.maybe_print_comment(pat.span.lo());
|
||||
self.ann.pre(self, AnnNode::Pat(pat));
|
||||
@@ -1774,7 +1910,7 @@ fn print_pat(&mut self, pat: &ast::Pat) {
|
||||
if let Some(p) = sub {
|
||||
self.space();
|
||||
self.word_space("@");
|
||||
self.print_pat(p);
|
||||
self.print_pat_paren_if_or(p);
|
||||
}
|
||||
}
|
||||
PatKind::TupleStruct(qself, path, elts) => {
|
||||
@@ -1846,7 +1982,7 @@ fn print_pat(&mut self, pat: &ast::Pat) {
|
||||
}
|
||||
PatKind::Box(inner) => {
|
||||
self.word("box ");
|
||||
self.print_pat(inner);
|
||||
self.print_pat_paren_if_or(inner);
|
||||
}
|
||||
PatKind::Deref(inner) => {
|
||||
self.word("deref!");
|
||||
@@ -1870,7 +2006,7 @@ fn print_pat(&mut self, pat: &ast::Pat) {
|
||||
self.print_pat(inner);
|
||||
self.pclose();
|
||||
} else {
|
||||
self.print_pat(inner);
|
||||
self.print_pat_paren_if_or(inner);
|
||||
}
|
||||
}
|
||||
PatKind::Expr(e) => self.print_expr(e, FixupContext::default()),
|
||||
@@ -1887,12 +2023,12 @@ fn print_pat(&mut self, pat: &ast::Pat) {
|
||||
self.print_expr(e, FixupContext::default());
|
||||
}
|
||||
}
|
||||
PatKind::Guard(subpat, condition) => {
|
||||
PatKind::Guard(subpat, guard) => {
|
||||
self.popen();
|
||||
self.print_pat(subpat);
|
||||
self.space();
|
||||
self.word_space("if");
|
||||
self.print_expr(condition, FixupContext::default());
|
||||
self.print_expr(&guard.cond, FixupContext::default());
|
||||
self.pclose();
|
||||
}
|
||||
PatKind::Slice(elts) => {
|
||||
|
||||
@@ -260,12 +260,15 @@ fn print_expr_method_call(
|
||||
//
|
||||
// loop { break x; }.method();
|
||||
//
|
||||
self.print_expr_cond_paren(
|
||||
receiver,
|
||||
receiver.precedence() < ExprPrecedence::Unambiguous,
|
||||
fixup.leftmost_subexpression_with_dot(),
|
||||
);
|
||||
let needs_paren = receiver.precedence() < ExprPrecedence::Unambiguous;
|
||||
self.print_expr_cond_paren(receiver, needs_paren, fixup.leftmost_subexpression_with_dot());
|
||||
|
||||
// If the receiver is an unsuffixed float literal like `0.`, insert
|
||||
// a space so the `.` of the method call doesn't merge with the
|
||||
// trailing dot: `0. .method()` instead of `0..method()`.
|
||||
if !needs_paren && expr_ends_with_dot(receiver) {
|
||||
self.word(" ");
|
||||
}
|
||||
self.word(".");
|
||||
self.print_ident(segment.ident);
|
||||
if let Some(args) = &segment.args {
|
||||
@@ -658,11 +661,15 @@ pub(super) fn print_expr_outer_attr_style(
|
||||
);
|
||||
}
|
||||
ast::ExprKind::Field(expr, ident) => {
|
||||
let needs_paren = expr.precedence() < ExprPrecedence::Unambiguous;
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < ExprPrecedence::Unambiguous,
|
||||
needs_paren,
|
||||
fixup.leftmost_subexpression_with_dot(),
|
||||
);
|
||||
if !needs_paren && expr_ends_with_dot(expr) {
|
||||
self.word(" ");
|
||||
}
|
||||
self.word(".");
|
||||
self.print_ident(*ident);
|
||||
}
|
||||
@@ -685,11 +692,15 @@ pub(super) fn print_expr_outer_attr_style(
|
||||
let fake_prec = ExprPrecedence::LOr;
|
||||
if let Some(e) = start {
|
||||
let start_fixup = fixup.leftmost_subexpression_with_operator(true);
|
||||
self.print_expr_cond_paren(
|
||||
e,
|
||||
start_fixup.precedence(e) < fake_prec,
|
||||
start_fixup,
|
||||
);
|
||||
let needs_paren = start_fixup.precedence(e) < fake_prec;
|
||||
self.print_expr_cond_paren(e, needs_paren, start_fixup);
|
||||
// If the start expression is a float literal ending with
|
||||
// `.`, we need a space before `..` or `..=` so that the
|
||||
// dots don't merge. E.g. `0. ..45.` must not become
|
||||
// `0...45.`.
|
||||
if !needs_paren && expr_ends_with_dot(e) {
|
||||
self.word(" ");
|
||||
}
|
||||
}
|
||||
match limits {
|
||||
ast::RangeLimits::HalfOpen => self.word(".."),
|
||||
@@ -880,9 +891,9 @@ fn print_arm(&mut self, arm: &ast::Arm) {
|
||||
self.print_outer_attributes(&arm.attrs);
|
||||
self.print_pat(&arm.pat);
|
||||
self.space();
|
||||
if let Some(e) = &arm.guard {
|
||||
if let Some(guard) = &arm.guard {
|
||||
self.word_space("if");
|
||||
self.print_expr(e, FixupContext::default());
|
||||
self.print_expr(&guard.cond, FixupContext::default());
|
||||
self.space();
|
||||
}
|
||||
|
||||
@@ -1025,3 +1036,18 @@ fn reconstruct_format_args_template_string(pieces: &[FormatArgsPiece]) -> String
|
||||
template.push('"');
|
||||
template
|
||||
}
|
||||
|
||||
/// Returns `true` if the printed representation of this expression ends with
|
||||
/// a `.` character — specifically, an unsuffixed float literal like `0.` or
|
||||
/// `45.`. This is used to insert whitespace before range operators (`..`,
|
||||
/// `..=`) so that the dots don't merge (e.g. `0. ..45.` instead of `0...45.`).
|
||||
fn expr_ends_with_dot(expr: &ast::Expr) -> bool {
|
||||
match &expr.kind {
|
||||
ast::ExprKind::Lit(token_lit) => {
|
||||
token_lit.kind == token::Float
|
||||
&& token_lit.suffix.is_none()
|
||||
&& token_lit.symbol.as_str().ends_with('.')
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -881,7 +881,13 @@ fn print_use_tree(&mut self, tree: &ast::UseTree) {
|
||||
}
|
||||
if items.is_empty() {
|
||||
self.word("{}");
|
||||
} else if let [(item, _)] = items.as_slice() {
|
||||
} else if let [(item, _)] = items.as_slice()
|
||||
&& !item
|
||||
.prefix
|
||||
.segments
|
||||
.first()
|
||||
.is_some_and(|seg| seg.ident.name == rustc_span::symbol::kw::SelfLower)
|
||||
{
|
||||
self.print_use_tree(item);
|
||||
} else {
|
||||
let cb = self.cbox(INDENT_UNIT);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
use crate::attributes::prelude::Allow;
|
||||
use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
|
||||
use crate::attributes::{OnDuplicate, SingleAttributeParser};
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::parser::{ArgParser, MetaItemOrLitParser};
|
||||
use crate::target_checking::AllowedTargets;
|
||||
@@ -18,12 +18,12 @@
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcAutodiffParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_autodiff];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||
Allow(Target::Method(MethodKind::Trait { body: false })),
|
||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
||||
]);
|
||||
const TEMPLATE: AttributeTemplate = template!(
|
||||
|
||||
@@ -20,7 +20,9 @@
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
use crate::context::{AcceptContext, ShouldEmit, Stage};
|
||||
use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser};
|
||||
use crate::parser::{
|
||||
AllowExprMetavar, ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser,
|
||||
};
|
||||
use crate::session_diagnostics::{
|
||||
AttributeParseError, AttributeParseErrorReason, CfgAttrBadDelim, MetaBadDelimSugg,
|
||||
ParsedDescription,
|
||||
@@ -363,6 +365,7 @@ fn parse_cfg_attr_internal<'a>(
|
||||
let meta = MetaItemOrLitParser::parse_single(
|
||||
parser,
|
||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
|
||||
AllowExprMetavar::Yes,
|
||||
)?;
|
||||
let pred_span = pred_start.with_hi(parser.token.span.hi());
|
||||
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{AttrStyle, NodeId, token};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_feature::{AttributeTemplate, Features};
|
||||
use rustc_hir::attrs::CfgEntry;
|
||||
use rustc_hir::{AttrPath, Target};
|
||||
use rustc_parse::exp;
|
||||
use rustc_parse::parser::{Parser, Recovery};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::lint::BuiltinLintDiag;
|
||||
use rustc_session::lint::builtin::UNREACHABLE_CFG_SELECT_PREDICATES;
|
||||
use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
|
||||
|
||||
use crate::parser::MetaItemOrLitParser;
|
||||
use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry};
|
||||
use crate::parser::{AllowExprMetavar, MetaItemOrLitParser};
|
||||
use crate::{AttributeParser, ParsedDescription, ShouldEmit, errors, parse_cfg_entry};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum CfgSelectPredicate {
|
||||
@@ -94,6 +94,7 @@ pub fn parse_cfg_select(
|
||||
let meta = MetaItemOrLitParser::parse_single(
|
||||
p,
|
||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
|
||||
AllowExprMetavar::Yes,
|
||||
)
|
||||
.map_err(|diag| diag.emit())?;
|
||||
let cfg_span = meta.span();
|
||||
@@ -152,11 +153,17 @@ fn lint_unreachable(
|
||||
|
||||
let branch_is_unreachable = |predicate: CfgSelectPredicate, wildcard_span| {
|
||||
let span = predicate.span();
|
||||
p.psess.buffer_lint(
|
||||
p.psess.dyn_buffer_lint(
|
||||
UNREACHABLE_CFG_SELECT_PREDICATES,
|
||||
span,
|
||||
lint_node_id,
|
||||
BuiltinLintDiag::UnreachableCfg { span, wildcard_span },
|
||||
move |dcx, level| match wildcard_span {
|
||||
Some(wildcard_span) => {
|
||||
errors::UnreachableCfgSelectPredicateWildcard { span, wildcard_span }
|
||||
.into_diag(dcx, level)
|
||||
}
|
||||
None => errors::UnreachableCfgSelectPredicate { span }.into_diag(dcx, level),
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ impl<S: Stage> SingleAttributeParser<S> for CfiEncodingParser {
|
||||
Allow(Target::Enum),
|
||||
Allow(Target::Union),
|
||||
]);
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "encoding");
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for OptimizeParser {
|
||||
const PATH: &[Symbol] = &[sym::optimize];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
@@ -68,7 +67,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for ColdParser {
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for CoverageParser {
|
||||
const PATH: &[Symbol] = &[sym::coverage];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
@@ -119,7 +117,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for ExportNameParser {
|
||||
const PATH: &[rustc_span::Symbol] = &[sym::export_name];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Static),
|
||||
@@ -157,7 +154,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcObjcClassParser {
|
||||
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)]);
|
||||
@@ -169,7 +165,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
||||
return None;
|
||||
};
|
||||
let Some(classname) = nv.value_as_str() else {
|
||||
// `#[rustc_objc_class = ...]` is expected to be used as an implementatioin detail
|
||||
// `#[rustc_objc_class = ...]` is expected to be used as an implementation 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 });
|
||||
@@ -189,7 +185,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcObjcSelectorParser {
|
||||
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)]);
|
||||
@@ -201,7 +196,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
||||
return None;
|
||||
};
|
||||
let Some(methname) = nv.value_as_str() else {
|
||||
// `#[rustc_objc_selector = ...]` is expected to be used as an implementatioin detail
|
||||
// `#[rustc_objc_selector = ...]` is expected to be used as an implementation 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 });
|
||||
@@ -587,6 +582,7 @@ impl<S: Stage> SingleAttributeParser<S> for SanitizeParser {
|
||||
r#"kernel_address = "on|off""#,
|
||||
r#"cfi = "on|off""#,
|
||||
r#"hwaddress = "on|off""#,
|
||||
r#"kernel_hwaddress = "on|off""#,
|
||||
r#"kcfi = "on|off""#,
|
||||
r#"memory = "on|off""#,
|
||||
r#"memtag = "on|off""#,
|
||||
@@ -595,7 +591,6 @@ impl<S: Stage> SingleAttributeParser<S> for SanitizeParser {
|
||||
r#"realtime = "nonblocking|blocking|caller""#,
|
||||
]);
|
||||
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
@@ -654,7 +649,9 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
||||
Some(sym::memtag) => apply(SanitizerSet::MEMTAG),
|
||||
Some(sym::shadow_call_stack) => apply(SanitizerSet::SHADOWCALLSTACK),
|
||||
Some(sym::thread) => apply(SanitizerSet::THREAD),
|
||||
Some(sym::hwaddress) => apply(SanitizerSet::HWADDRESS),
|
||||
Some(sym::hwaddress) | Some(sym::kernel_hwaddress) => {
|
||||
apply(SanitizerSet::HWADDRESS | SanitizerSet::KERNELHWADDRESS)
|
||||
}
|
||||
Some(sym::realtime) => match value.value_as_str() {
|
||||
Some(sym::nonblocking) => rtsan = Some(RtsanSetting::Nonblocking),
|
||||
Some(sym::blocking) => rtsan = Some(RtsanSetting::Blocking),
|
||||
@@ -671,6 +668,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
||||
item.path().span(),
|
||||
&[
|
||||
sym::address,
|
||||
sym::kernel_address,
|
||||
sym::cfi,
|
||||
sym::kcfi,
|
||||
sym::memory,
|
||||
@@ -678,6 +676,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
||||
sym::shadow_call_stack,
|
||||
sym::thread,
|
||||
sym::hwaddress,
|
||||
sym::kernel_hwaddress,
|
||||
sym::realtime,
|
||||
],
|
||||
);
|
||||
@@ -723,7 +722,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcEiiForeignItemParser {
|
||||
impl<S: Stage> SingleAttributeParser<S> for PatchableFunctionEntryParser {
|
||||
const PATH: &[Symbol] = &[sym::patchable_function_entry];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["prefix_nops = m, entry_nops = n"]);
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for CrateNameParser {
|
||||
const PATH: &[Symbol] = &[sym::crate_name];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
@@ -84,7 +83,6 @@ fn extend(
|
||||
|
||||
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::AllowList(&[Allow(Target::Crate)]);
|
||||
@@ -107,7 +105,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
||||
|
||||
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::AllowList(&[Allow(Target::Crate)]);
|
||||
@@ -130,7 +127,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
||||
|
||||
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::AllowList(&[Allow(Target::Crate)]);
|
||||
@@ -153,7 +149,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
||||
|
||||
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::AllowList(&[Allow(Target::Crate)]);
|
||||
@@ -213,7 +208,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcCoherenceIsCoreParser {
|
||||
impl<S: Stage> SingleAttributeParser<S> for WindowsSubsystemParser {
|
||||
const PATH: &[Symbol] = &[sym::windows_subsystem];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: ["windows", "console"], "https://doc.rust-lang.org/reference/runtime.html#the-windows_subsystem-attribute");
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ fn get<S: Stage>(
|
||||
pub(crate) struct DeprecatedParser;
|
||||
impl<S: Stage> SingleAttributeParser<S> for DeprecatedParser {
|
||||
const PATH: &[Symbol] = &[sym::deprecated];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
|
||||
Allow(Target::Fn),
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES;
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
|
||||
use crate::attributes::{OnDuplicate, SingleAttributeParser};
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::parser::ArgParser;
|
||||
use crate::target_checking::{ALL_TARGETS, AllowedTargets};
|
||||
@@ -12,7 +12,6 @@
|
||||
pub(crate) struct DoNotRecommendParser;
|
||||
impl<S: Stage> SingleAttributeParser<S> for DoNotRecommendParser {
|
||||
const PATH: &[Symbol] = &[sym::diagnostic, sym::do_not_recommend];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); // Checked in check_attr.
|
||||
const TEMPLATE: AttributeTemplate = template!(Word /*doesn't matter */);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
pub(crate) mod do_not_recommend;
|
||||
pub(crate) mod on_const;
|
||||
pub(crate) mod on_move;
|
||||
pub(crate) mod on_unimplemented;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
@@ -32,6 +33,8 @@ pub(crate) enum Mode {
|
||||
DiagnosticOnUnimplemented,
|
||||
/// `#[diagnostic::on_const]`
|
||||
DiagnosticOnConst,
|
||||
/// `#[diagnostic::on_move]`
|
||||
DiagnosticOnMove,
|
||||
}
|
||||
|
||||
fn merge_directives<S: Stage>(
|
||||
@@ -113,6 +116,13 @@ fn parse_directive_items<'p, S: Stage>(
|
||||
span,
|
||||
);
|
||||
}
|
||||
Mode::DiagnosticOnMove => {
|
||||
cx.emit_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
AttributeLintKind::MalformedOnMoveAttr { span },
|
||||
span,
|
||||
);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}}
|
||||
@@ -132,7 +142,7 @@ fn parse_directive_items<'p, S: Stage>(
|
||||
Mode::RustcOnUnimplemented => {
|
||||
cx.emit_err(NoValueInOnUnimplemented { span: item.span() });
|
||||
}
|
||||
Mode::DiagnosticOnUnimplemented |Mode::DiagnosticOnConst => {
|
||||
Mode::DiagnosticOnUnimplemented |Mode::DiagnosticOnConst | Mode::DiagnosticOnMove => {
|
||||
cx.emit_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
AttributeLintKind::IgnoredDiagnosticOption {
|
||||
@@ -460,11 +470,12 @@ fn parse_filter(input: Symbol) -> FilterFormatString {
|
||||
// if the integer type has been resolved, to allow targeting all integers.
|
||||
// `"{integer}"` and `"{float}"` come from numerics that haven't been inferred yet,
|
||||
// from the `Display` impl of `InferTy` to be precise.
|
||||
// `"{union|enum|struct}"` is used as a special selector for ADTs.
|
||||
//
|
||||
// Don't try to format these later!
|
||||
Position::ArgumentNamed(arg @ ("integer" | "integral" | "float")) => {
|
||||
LitOrArg::Lit(Symbol::intern(&format!("{{{arg}}}")))
|
||||
}
|
||||
Position::ArgumentNamed(
|
||||
arg @ ("integer" | "integral" | "float" | "union" | "enum" | "struct"),
|
||||
) => LitOrArg::Lit(Symbol::intern(&format!("{{{arg}}}"))),
|
||||
|
||||
Position::ArgumentNamed(arg) => LitOrArg::Arg(Symbol::intern(arg)),
|
||||
Position::ArgumentImplicitlyIs(_) => LitOrArg::Lit(sym::empty_braces),
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
use rustc_feature::template;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES;
|
||||
use rustc_span::sym;
|
||||
|
||||
use crate::attributes::diagnostic::*;
|
||||
use crate::attributes::prelude::*;
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::parser::ArgParser;
|
||||
use crate::target_checking::{ALL_TARGETS, AllowedTargets};
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct OnMoveParser {
|
||||
span: Option<Span>,
|
||||
directive: Option<(Span, Directive)>,
|
||||
}
|
||||
|
||||
impl OnMoveParser {
|
||||
fn parse<'sess, S: Stage>(
|
||||
&mut self,
|
||||
cx: &mut AcceptContext<'_, 'sess, S>,
|
||||
args: &ArgParser,
|
||||
mode: Mode,
|
||||
) {
|
||||
if !cx.features().diagnostic_on_move() {
|
||||
return;
|
||||
}
|
||||
|
||||
let span = cx.attr_span;
|
||||
self.span = Some(span);
|
||||
let Some(list) = args.list() else {
|
||||
cx.emit_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
AttributeLintKind::MissingOptionsForOnMove,
|
||||
span,
|
||||
);
|
||||
return;
|
||||
};
|
||||
|
||||
if list.is_empty() {
|
||||
cx.emit_lint(
|
||||
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
AttributeLintKind::OnMoveMalformedAttrExpectedLiteralOrDelimiter,
|
||||
list.span,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(directive) = parse_directive_items(cx, mode, list.mixed(), true) {
|
||||
merge_directives(cx, &mut self.directive, (span, directive));
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<S: Stage> AttributeParser<S> for OnMoveParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
|
||||
&[sym::diagnostic, sym::on_move],
|
||||
template!(List: &[r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#]),
|
||||
|this, cx, args| {
|
||||
this.parse(cx, args, Mode::DiagnosticOnMove);
|
||||
},
|
||||
)];
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
|
||||
|
||||
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
if let Some(span) = self.span {
|
||||
Some(AttributeKind::OnMove { span, directive: self.directive.map(|d| Box::new(d.1)) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
|
||||
use crate::attributes::{OnDuplicate, SingleAttributeParser};
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::parser::ArgParser;
|
||||
use crate::target_checking::{ALL_TARGETS, AllowedTargets};
|
||||
@@ -10,7 +10,6 @@
|
||||
pub(crate) struct RustcDummyParser;
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcDummyParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_dummy];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
|
||||
const TEMPLATE: AttributeTemplate = template!(Word); // Anything, really
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for InlineParser {
|
||||
const PATH: &[Symbol] = &[sym::inline];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
@@ -68,7 +67,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_force_inline];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
|
||||
@@ -16,7 +16,6 @@ impl<S: Stage> SingleAttributeParser<S> for InstructionSetParser {
|
||||
]);
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["set"], "https://doc.rust-lang.org/reference/attributes/codegen.html#the-instruction_set-attribute");
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
const POSSIBLE_SYMBOLS: &[Symbol] = &[sym::arm_a32, sym::arm_t32];
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for LinkNameParser {
|
||||
const PATH: &[Symbol] = &[sym::link_name];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
|
||||
Allow(Target::ForeignFn),
|
||||
@@ -466,7 +465,6 @@ fn parse_link_import_name_type<S: Stage>(
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
|
||||
const PATH: &[Symbol] = &[sym::link_section];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
|
||||
Allow(Target::Static),
|
||||
@@ -541,7 +539,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcStdInternalSymbolParser {
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for LinkOrdinalParser {
|
||||
const PATH: &[Symbol] = &[sym::link_ordinal];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::ForeignFn),
|
||||
@@ -583,8 +580,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
||||
impl<S: Stage> SingleAttributeParser<S> for LinkageParser {
|
||||
const PATH: &[Symbol] = &[sym::linkage];
|
||||
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
|
||||
@@ -130,7 +130,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for AllowInternalUnsafeParser {
|
||||
|
||||
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(&[
|
||||
@@ -168,7 +167,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for CollapseDebugInfoParser {
|
||||
const PATH: &[Symbol] = &[sym::collapse_debuginfo];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const TEMPLATE: AttributeTemplate = template!(
|
||||
List: &["no", "external", "yes"],
|
||||
|
||||
@@ -124,14 +124,8 @@ pub(crate) trait SingleAttributeParser<S: Stage>: 'static {
|
||||
/// If you need the parser to accept more than one path, use [`AttributeParser`] instead
|
||||
const PATH: &[Symbol];
|
||||
|
||||
/// Configures the precedence of attributes with the same `PATH` on a syntax node.
|
||||
const ATTRIBUTE_ORDER: AttributeOrder;
|
||||
|
||||
/// Configures what to do when when the same attribute is
|
||||
/// applied more than once on the same syntax node.
|
||||
///
|
||||
/// [`ATTRIBUTE_ORDER`](Self::ATTRIBUTE_ORDER) specified which one is assumed to be correct,
|
||||
/// and this specified whether to, for example, warn or error on the other one.
|
||||
const ON_DUPLICATE: OnDuplicate<S>;
|
||||
|
||||
const ALLOWED_TARGETS: AllowedTargets;
|
||||
@@ -162,21 +156,8 @@ impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S>
|
||||
<T as SingleAttributeParser<S>>::TEMPLATE,
|
||||
|group: &mut Single<T, S>, cx, args| {
|
||||
if let Some(pa) = T::convert(cx, args) {
|
||||
match T::ATTRIBUTE_ORDER {
|
||||
// keep the first and report immediately. ignore this attribute
|
||||
AttributeOrder::KeepInnermost => {
|
||||
if let Some((_, unused)) = group.1 {
|
||||
T::ON_DUPLICATE.exec::<T>(cx, cx.attr_span, unused);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// keep the new one and warn about the previous,
|
||||
// then replace
|
||||
AttributeOrder::KeepOutermost => {
|
||||
if let Some((_, used)) = group.1 {
|
||||
T::ON_DUPLICATE.exec::<T>(cx, used, cx.attr_span);
|
||||
}
|
||||
}
|
||||
if let Some((_, used)) = group.1 {
|
||||
T::ON_DUPLICATE.exec::<T>(cx, used, cx.attr_span);
|
||||
}
|
||||
|
||||
group.1 = Some((pa, cx.attr_span));
|
||||
@@ -206,7 +187,7 @@ pub(crate) enum OnDuplicate<S: Stage> {
|
||||
/// Custom function called when a duplicate attribute is found.
|
||||
///
|
||||
/// - `unused` is the span of the attribute that was unused or bad because of some
|
||||
/// duplicate reason (see [`AttributeOrder`])
|
||||
/// duplicate reason
|
||||
/// - `used` is the span of the attribute that was used in favor of the unused attribute
|
||||
Custom(fn(cx: &AcceptContext<'_, '_, S>, used: Span, unused: Span)),
|
||||
}
|
||||
@@ -223,8 +204,8 @@ fn exec<P: SingleAttributeParser<S>>(
|
||||
OnDuplicate::WarnButFutureError => cx.warn_unused_duplicate_future_error(used, unused),
|
||||
OnDuplicate::Error => {
|
||||
cx.emit_err(UnusedMultiple {
|
||||
this: used,
|
||||
other: unused,
|
||||
this: unused,
|
||||
other: used,
|
||||
name: Symbol::intern(
|
||||
&P::PATH.into_iter().map(|i| i.to_string()).collect::<Vec<_>>().join(".."),
|
||||
),
|
||||
@@ -236,30 +217,6 @@ fn exec<P: SingleAttributeParser<S>>(
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) enum AttributeOrder {
|
||||
/// Duplicates after the innermost instance of the attribute will be an error/warning.
|
||||
/// Only keep the lowest attribute.
|
||||
///
|
||||
/// Attributes are processed from bottom to top, so this raises a warning/error on all the attributes
|
||||
/// further above the lowest one:
|
||||
/// ```
|
||||
/// #[stable(since="1.0")] //~ WARNING duplicated attribute
|
||||
/// #[stable(since="2.0")]
|
||||
/// ```
|
||||
KeepInnermost,
|
||||
|
||||
/// Duplicates before the outermost instance of the attribute will be an error/warning.
|
||||
/// Only keep the highest attribute.
|
||||
///
|
||||
/// Attributes are processed from bottom to top, so this raises a warning/error on all the attributes
|
||||
/// below the highest one:
|
||||
/// ```
|
||||
/// #[path="foo.rs"]
|
||||
/// #[path="bar.rs"] //~ WARNING duplicated attribute
|
||||
/// ```
|
||||
KeepOutermost,
|
||||
}
|
||||
|
||||
/// An even simpler version of [`SingleAttributeParser`]:
|
||||
/// now automatically check that there are no arguments provided to the attribute.
|
||||
///
|
||||
@@ -284,7 +241,6 @@ fn default() -> Self {
|
||||
|
||||
impl<T: NoArgsAttributeParser<S>, S: Stage> SingleAttributeParser<S> for WithoutArgs<T, S> {
|
||||
const PATH: &[Symbol] = T::PATH;
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = T::ON_DUPLICATE;
|
||||
const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word);
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for MustNotSuspendParser {
|
||||
const PATH: &[rustc_span::Symbol] = &[sym::must_not_suspend];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Struct),
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for MustUseParser {
|
||||
const PATH: &[Symbol] = &[sym::must_use];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
|
||||
Allow(Target::Fn),
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for PathParser {
|
||||
const PATH: &[Symbol] = &[sym::path];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const ALLOWED_TARGETS: AllowedTargets =
|
||||
AllowedTargets::AllowListWarnRest(&[Allow(Target::Mod), Error(Target::Crate)]);
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
|
||||
#[doc(hidden)]
|
||||
pub(super) use crate::attributes::{
|
||||
AcceptMapping, AttributeOrder, AttributeParser, CombineAttributeParser, ConvertFn,
|
||||
NoArgsAttributeParser, OnDuplicate, SingleAttributeParser,
|
||||
AcceptMapping, AttributeParser, CombineAttributeParser, ConvertFn, NoArgsAttributeParser,
|
||||
OnDuplicate, SingleAttributeParser,
|
||||
};
|
||||
// contexts
|
||||
#[doc(hidden)]
|
||||
|
||||
@@ -25,7 +25,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for ProcMacroAttributeParser {
|
||||
pub(crate) struct ProcMacroDeriveParser;
|
||||
impl<S: Stage> SingleAttributeParser<S> for ProcMacroDeriveParser {
|
||||
const PATH: &[Symbol] = &[sym::proc_macro_derive];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = PROC_MACRO_ALLOWED_TARGETS;
|
||||
const TEMPLATE: AttributeTemplate = template!(
|
||||
@@ -46,7 +45,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
||||
pub(crate) struct RustcBuiltinMacroParser;
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcBuiltinMacroParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_builtin_macro];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]);
|
||||
const TEMPLATE: AttributeTemplate =
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
use rustc_hir::attrs::{AttributeKind, MirDialect, MirPhase};
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
use super::{AttributeOrder, OnDuplicate};
|
||||
use super::OnDuplicate;
|
||||
use crate::attributes::SingleAttributeParser;
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::parser::ArgParser;
|
||||
use crate::session_diagnostics;
|
||||
use crate::target_checking::AllowedTargets;
|
||||
use crate::target_checking::Policy::Allow;
|
||||
|
||||
@@ -17,8 +18,6 @@
|
||||
impl<S: Stage> SingleAttributeParser<S> for CustomMirParser {
|
||||
const PATH: &[rustc_span::Symbol] = &[sym::custom_mir];
|
||||
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
||||
@@ -57,6 +56,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
||||
|
||||
let dialect = parse_dialect(cx, dialect, &mut failed);
|
||||
let phase = parse_phase(cx, phase, &mut failed);
|
||||
check_custom_mir(cx, dialect, phase, &mut failed);
|
||||
|
||||
if failed {
|
||||
return None;
|
||||
@@ -138,3 +138,51 @@ fn parse_phase<S: Stage>(
|
||||
|
||||
Some((phase, span))
|
||||
}
|
||||
|
||||
fn check_custom_mir<S: Stage>(
|
||||
cx: &mut AcceptContext<'_, '_, S>,
|
||||
dialect: Option<(MirDialect, Span)>,
|
||||
phase: Option<(MirPhase, Span)>,
|
||||
failed: &mut bool,
|
||||
) {
|
||||
let attr_span = cx.attr_span;
|
||||
let Some((dialect, dialect_span)) = dialect else {
|
||||
if let Some((_, phase_span)) = phase {
|
||||
*failed = true;
|
||||
cx.emit_err(session_diagnostics::CustomMirPhaseRequiresDialect {
|
||||
attr_span,
|
||||
phase_span,
|
||||
});
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
match dialect {
|
||||
MirDialect::Analysis => {
|
||||
if let Some((MirPhase::Optimized, phase_span)) = phase {
|
||||
*failed = true;
|
||||
cx.emit_err(session_diagnostics::CustomMirIncompatibleDialectAndPhase {
|
||||
dialect,
|
||||
phase: MirPhase::Optimized,
|
||||
attr_span,
|
||||
dialect_span,
|
||||
phase_span,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
MirDialect::Built => {
|
||||
if let Some((phase, phase_span)) = phase {
|
||||
*failed = true;
|
||||
cx.emit_err(session_diagnostics::CustomMirIncompatibleDialectAndPhase {
|
||||
dialect,
|
||||
phase,
|
||||
attr_span,
|
||||
dialect_span,
|
||||
phase_span,
|
||||
});
|
||||
}
|
||||
}
|
||||
MirDialect::Runtime => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ impl<S: Stage> SingleAttributeParser<S> for RustcAllocatorZeroedVariantParser {
|
||||
const ALLOWED_TARGETS: AllowedTargets =
|
||||
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "function");
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let Some(name) = args.name_value().and_then(NameValueParser::value_as_str) else {
|
||||
cx.expected_name_value(cx.attr_span, None);
|
||||
|
||||
@@ -31,7 +31,6 @@ impl<S: Stage> SingleAttributeParser<S> for RustcMustImplementOneOfParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_must_implement_one_of];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["function1, function2, ..."]);
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let Some(list) = args.list() else {
|
||||
@@ -105,7 +104,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcNoImplicitAutorefsParser {
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeStartParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_layout_scalar_valid_range_start];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["start"]);
|
||||
@@ -120,7 +118,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeEndParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_layout_scalar_valid_range_end];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["end"]);
|
||||
@@ -135,7 +132,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcLegacyConstGenericsParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_legacy_const_generics];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["N"]);
|
||||
@@ -193,7 +189,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcInheritOverflowChecksParser {
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcLintOptDenyFieldAccessParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_lint_opt_deny_field_access];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Field)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(Word);
|
||||
@@ -373,7 +368,6 @@ impl<S: Stage> SingleAttributeParser<S> for RustcDeprecatedSafe2024Parser {
|
||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
||||
]);
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &[r#"audit_that = "...""#]);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
@@ -441,7 +435,6 @@ impl<S: Stage> SingleAttributeParser<S> for RustcNeverTypeOptionsParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_never_type_options];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &[
|
||||
r#"fallback = "unit", "never", "no""#,
|
||||
r#"diverging_block_default = "unit", "never""#,
|
||||
@@ -592,7 +585,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcLintUntrackedQueryInformationPa
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcSimdMonomorphizeLaneLimitParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_simd_monomorphize_lane_limit];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
|
||||
@@ -610,7 +602,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcScalableVectorParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_scalable_vector];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(Word, List: &["count"]);
|
||||
@@ -636,7 +627,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for LangParser {
|
||||
const PATH: &[Symbol] = &[sym::lang];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); // Targets are checked per lang item in `rustc_passes`
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
|
||||
@@ -981,8 +971,6 @@ fn extend(
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcIfThisChangedParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_if_this_changed];
|
||||
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
@@ -1147,7 +1135,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcEffectiveVisibilityParser {
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcDiagnosticItemParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_diagnostic_item];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Trait),
|
||||
@@ -1220,7 +1207,6 @@ impl<S: Stage> SingleAttributeParser<S> for RustcSymbolNameParser {
|
||||
Allow(Target::Impl { of_trait: false }),
|
||||
]);
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word);
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
if let Err(span) = args.no_args() {
|
||||
@@ -1245,7 +1231,6 @@ impl<S: Stage> SingleAttributeParser<S> for RustcDefPathParser {
|
||||
Allow(Target::Impl { of_trait: false }),
|
||||
]);
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word);
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
if let Err(span) = args.no_args() {
|
||||
@@ -1275,7 +1260,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcStrictCoherenceParser {
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcReservationImplParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_reservation_impl];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets =
|
||||
AllowedTargets::AllowList(&[Allow(Target::Impl { of_trait: true })]);
|
||||
@@ -1311,7 +1295,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for PreludeImportParser {
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcDocPrimitiveParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_doc_primitive];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Mod)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "primitive name");
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use std::num::NonZero;
|
||||
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_feature::ACCEPTED_LANG_FEATURES;
|
||||
use rustc_hir::target::GenericParamKind;
|
||||
use rustc_hir::{
|
||||
DefaultBodyStability, MethodKind, PartialConstStability, Stability, StabilityLevel,
|
||||
@@ -366,7 +367,7 @@ pub(crate) fn parse_stability<S: Stage>(
|
||||
}
|
||||
}
|
||||
|
||||
// Read the content of a `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable`
|
||||
/// Read the content of a `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable`
|
||||
/// attribute, and return the feature name and its stability information.
|
||||
pub(crate) fn parse_unstability<S: Stage>(
|
||||
cx: &AcceptContext<'_, '_, S>,
|
||||
@@ -376,7 +377,6 @@ pub(crate) fn parse_unstability<S: Stage>(
|
||||
let mut reason = None;
|
||||
let mut issue = None;
|
||||
let mut issue_num = None;
|
||||
let mut is_soft = false;
|
||||
let mut implied_by = None;
|
||||
let mut old_name = None;
|
||||
|
||||
@@ -423,12 +423,6 @@ pub(crate) fn parse_unstability<S: Stage>(
|
||||
},
|
||||
};
|
||||
}
|
||||
Some(sym::soft) => {
|
||||
if let Err(span) = args.no_args() {
|
||||
cx.emit_err(session_diagnostics::SoftNoArgs { span });
|
||||
}
|
||||
is_soft = true;
|
||||
}
|
||||
Some(sym::implied_by) => {
|
||||
insert_value_into_option_or_error(cx, ¶m, &mut implied_by, word.unwrap())?
|
||||
}
|
||||
@@ -438,14 +432,7 @@ pub(crate) fn parse_unstability<S: Stage>(
|
||||
_ => {
|
||||
cx.expected_specific_argument(
|
||||
param.span(),
|
||||
&[
|
||||
sym::feature,
|
||||
sym::reason,
|
||||
sym::issue,
|
||||
sym::soft,
|
||||
sym::implied_by,
|
||||
sym::old_name,
|
||||
],
|
||||
&[sym::feature, sym::reason, sym::issue, sym::implied_by, sym::old_name],
|
||||
);
|
||||
return None;
|
||||
}
|
||||
@@ -465,10 +452,19 @@ pub(crate) fn parse_unstability<S: Stage>(
|
||||
|
||||
match (feature, issue) {
|
||||
(Ok(feature), Ok(_)) => {
|
||||
// Stable *language* features shouldn't be used as unstable library features.
|
||||
// (Not doing this for stable library features is checked by tidy.)
|
||||
if ACCEPTED_LANG_FEATURES.iter().any(|f| f.name == feature) {
|
||||
cx.emit_err(session_diagnostics::UnstableAttrForAlreadyStableFeature {
|
||||
attr_span: cx.attr_span,
|
||||
item_span: cx.target_span,
|
||||
});
|
||||
return None;
|
||||
}
|
||||
|
||||
let level = StabilityLevel::Unstable {
|
||||
reason: UnstableReason::from_opt_reason(reason),
|
||||
issue: issue_num,
|
||||
is_soft,
|
||||
implied_by,
|
||||
old_name,
|
||||
};
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for IgnoreParser {
|
||||
const PATH: &[Symbol] = &[sym::ignore];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets =
|
||||
AllowedTargets::AllowListWarnRest(&[Allow(Target::Fn), Error(Target::WherePredicate)]);
|
||||
@@ -41,7 +40,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for ShouldPanicParser {
|
||||
const PATH: &[Symbol] = &[sym::should_panic];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const ALLOWED_TARGETS: AllowedTargets =
|
||||
AllowedTargets::AllowListWarnRest(&[Allow(Target::Fn), Error(Target::WherePredicate)]);
|
||||
@@ -98,7 +96,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
||||
impl<S: Stage> SingleAttributeParser<S> for ReexportTestHarnessMainParser {
|
||||
const PATH: &[Symbol] = &[sym::reexport_test_harness_main];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
|
||||
|
||||
@@ -126,7 +123,6 @@ impl<S: Stage> SingleAttributeParser<S> for RustcAbiParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_abi];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const TEMPLATE: AttributeTemplate = template!(OneOf: &[sym::debug, sym::assert_eq]);
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::TyAlias),
|
||||
Allow(Target::Fn),
|
||||
@@ -197,7 +193,6 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcEvaluateWhereClausesParser {
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for TestRunnerParser {
|
||||
const PATH: &[Symbol] = &[sym::test_runner];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["path"]);
|
||||
@@ -226,7 +221,6 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcTestMarkerParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_test_marker];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Const),
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
use std::mem;
|
||||
|
||||
use super::prelude::*;
|
||||
use crate::attributes::{
|
||||
AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser,
|
||||
};
|
||||
use crate::attributes::{NoArgsAttributeParser, OnDuplicate, SingleAttributeParser};
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::parser::ArgParser;
|
||||
use crate::target_checking::Policy::{Allow, Warn};
|
||||
@@ -12,7 +10,6 @@
|
||||
pub(crate) struct RustcSkipDuringMethodDispatchParser;
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcSkipDuringMethodDispatchParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_skip_during_method_dispatch];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcMacroTransparencyParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_macro_transparency];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Custom(|cx, used, unused| {
|
||||
cx.dcx().span_err(vec![used, unused], "multiple macro transparency attributes");
|
||||
});
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
use crate::attributes::deprecation::*;
|
||||
use crate::attributes::diagnostic::do_not_recommend::*;
|
||||
use crate::attributes::diagnostic::on_const::*;
|
||||
use crate::attributes::diagnostic::on_move::*;
|
||||
use crate::attributes::diagnostic::on_unimplemented::*;
|
||||
use crate::attributes::doc::*;
|
||||
use crate::attributes::dummy::*;
|
||||
@@ -149,6 +150,7 @@ mod late {
|
||||
MacroUseParser,
|
||||
NakedParser,
|
||||
OnConstParser,
|
||||
OnMoveParser,
|
||||
OnUnimplementedParser,
|
||||
RustcAlignParser,
|
||||
RustcAlignStaticParser,
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
use rustc_errors::MultiSpan;
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`{$name}` attribute cannot be used at crate level")]
|
||||
pub(crate) struct InvalidAttrAtCrateLevel {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(
|
||||
"perhaps you meant to use an outer attribute",
|
||||
code = "#[",
|
||||
applicability = "machine-applicable",
|
||||
style = "verbose"
|
||||
)]
|
||||
pub pound_to_opening_bracket: Span,
|
||||
pub name: Symbol,
|
||||
#[subdiagnostic]
|
||||
pub item: Option<ItemFollowingInnerAttr>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Subdiagnostic)]
|
||||
#[label("the inner attribute doesn't annotate this item")]
|
||||
pub(crate) struct ItemFollowingInnerAttr {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("unreachable configuration predicate")]
|
||||
pub(crate) struct UnreachableCfgSelectPredicate {
|
||||
#[label("this configuration predicate is never reached")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("most attributes are not supported in `where` clauses")]
|
||||
#[help("only `#[cfg]` and `#[cfg_attr]` are supported")]
|
||||
pub(crate) struct UnsupportedAttributesInWhere {
|
||||
#[primary_span]
|
||||
pub span: MultiSpan,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("unreachable configuration predicate")]
|
||||
pub(crate) struct UnreachableCfgSelectPredicateWildcard {
|
||||
#[label("this configuration predicate is never reached")]
|
||||
pub span: Span,
|
||||
|
||||
#[label("always matches")]
|
||||
pub wildcard_span: Span,
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
use crate::context::{AcceptContext, FinalizeContext, FinalizeFn, SharedContext, Stage};
|
||||
use crate::early_parsed::{EARLY_PARSED_ATTRIBUTES, EarlyParsedState};
|
||||
use crate::parser::{ArgParser, PathParser, RefPathParser};
|
||||
use crate::parser::{AllowExprMetavar, ArgParser, PathParser, RefPathParser};
|
||||
use crate::session_diagnostics::ParsedDescription;
|
||||
use crate::{Early, Late, OmitDoc, ShouldEmit};
|
||||
|
||||
@@ -139,6 +139,7 @@ pub fn parse_single<T>(
|
||||
emit_errors: ShouldEmit,
|
||||
parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser) -> Option<T>,
|
||||
template: &AttributeTemplate,
|
||||
allow_expr_metavar: AllowExprMetavar,
|
||||
) -> Option<T> {
|
||||
let ast::AttrKind::Normal(normal_attr) = &attr.kind else {
|
||||
panic!("parse_single called on a doc attr")
|
||||
@@ -152,6 +153,7 @@ pub fn parse_single<T>(
|
||||
&parts,
|
||||
&sess.psess,
|
||||
emit_errors,
|
||||
allow_expr_metavar,
|
||||
)?;
|
||||
Self::parse_single_args(
|
||||
sess,
|
||||
@@ -267,6 +269,11 @@ pub fn parse_attribute_list(
|
||||
mut emit_lint: impl FnMut(LintId, Span, AttributeLintKind),
|
||||
) -> Vec<Attribute> {
|
||||
let mut attributes = Vec::new();
|
||||
// We store the attributes we intend to discard at the end of this function in order to
|
||||
// check they are applied to the right target and error out if necessary. In practice, we
|
||||
// end up dropping only derive attributes and derive helpers, both being fully processed
|
||||
// at macro expansion.
|
||||
let mut dropped_attributes = Vec::new();
|
||||
let mut attr_paths: Vec<RefPathParser<'_>> = Vec::new();
|
||||
let mut early_parsed_state = EarlyParsedState::default();
|
||||
|
||||
@@ -302,7 +309,7 @@ pub fn parse_attribute_list(
|
||||
kind: DocFragmentKind::Sugared(*comment_kind),
|
||||
span: attr_span,
|
||||
comment: *symbol,
|
||||
}))
|
||||
}));
|
||||
}
|
||||
ast::AttrKind::Normal(n) => {
|
||||
attr_paths.push(PathParser(&n.item.path));
|
||||
@@ -333,6 +340,7 @@ pub fn parse_attribute_list(
|
||||
&parts,
|
||||
&self.sess.psess,
|
||||
self.stage.should_emit(),
|
||||
AllowExprMetavar::No,
|
||||
) else {
|
||||
continue;
|
||||
};
|
||||
@@ -390,29 +398,33 @@ pub fn parse_attribute_list(
|
||||
Self::check_target(&accept.allowed_targets, target, &mut cx);
|
||||
}
|
||||
} else {
|
||||
// If we're here, we must be compiling a tool attribute... Or someone
|
||||
// forgot to parse their fancy new attribute. Let's warn them in any case.
|
||||
// If you are that person, and you really think your attribute should
|
||||
// remain unparsed, carefully read the documentation in this module and if
|
||||
// you still think so you can add an exception to this assertion.
|
||||
|
||||
// FIXME(jdonszelmann): convert other attributes, and check with this that
|
||||
// we caught em all
|
||||
// const FIXME_TEMPORARY_ATTR_ALLOWLIST: &[Symbol] = &[sym::cfg];
|
||||
// assert!(
|
||||
// self.tools.contains(&parts[0]) || true,
|
||||
// // || FIXME_TEMPORARY_ATTR_ALLOWLIST.contains(&parts[0]),
|
||||
// "attribute {path} wasn't parsed and isn't a know tool attribute",
|
||||
// );
|
||||
|
||||
attributes.push(Attribute::Unparsed(Box::new(AttrItem {
|
||||
let attr = AttrItem {
|
||||
path: attr_path.clone(),
|
||||
args: self
|
||||
.lower_attr_args(n.item.args.unparsed_ref().unwrap(), lower_span),
|
||||
id: HashIgnoredAttrId { attr_id: attr.id },
|
||||
style: attr.style,
|
||||
span: attr_span,
|
||||
})));
|
||||
};
|
||||
|
||||
if !matches!(self.stage.should_emit(), ShouldEmit::Nothing)
|
||||
&& target == Target::Crate
|
||||
{
|
||||
self.check_invalid_crate_level_attr_item(&attr, n.item.span());
|
||||
}
|
||||
|
||||
let attr = Attribute::Unparsed(Box::new(attr));
|
||||
|
||||
if self.tools.contains(&parts[0])
|
||||
// FIXME: this can be removed once #152369 has been merged.
|
||||
// https://github.com/rust-lang/rust/pull/152369
|
||||
|| [sym::allow, sym::deny, sym::expect, sym::forbid, sym::warn]
|
||||
.contains(&parts[0])
|
||||
{
|
||||
attributes.push(attr);
|
||||
} else {
|
||||
dropped_attributes.push(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -428,6 +440,12 @@ pub fn parse_attribute_list(
|
||||
}
|
||||
}
|
||||
|
||||
if !matches!(self.stage.should_emit(), ShouldEmit::Nothing)
|
||||
&& target == Target::WherePredicate
|
||||
{
|
||||
self.check_invalid_where_predicate_attrs(attributes.iter().chain(&dropped_attributes));
|
||||
}
|
||||
|
||||
attributes
|
||||
}
|
||||
|
||||
|
||||
@@ -79,6 +79,7 @@
|
||||
// tidy-alphabetical-start
|
||||
#![feature(decl_macro)]
|
||||
#![feature(iter_intersperse)]
|
||||
#![feature(try_blocks)]
|
||||
#![recursion_limit = "256"]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
@@ -99,6 +100,7 @@
|
||||
pub mod parser;
|
||||
|
||||
mod early_parsed;
|
||||
mod errors;
|
||||
mod safety;
|
||||
mod session_diagnostics;
|
||||
mod target_checking;
|
||||
|
||||
@@ -109,6 +109,7 @@ pub fn from_attr_args<'sess>(
|
||||
parts: &[Symbol],
|
||||
psess: &'sess ParseSess,
|
||||
should_emit: ShouldEmit,
|
||||
allow_expr_metavar: AllowExprMetavar,
|
||||
) -> Option<Self> {
|
||||
Some(match value {
|
||||
AttrArgs::Empty => Self::NoArgs,
|
||||
@@ -122,6 +123,7 @@ pub fn from_attr_args<'sess>(
|
||||
args.dspan.entire(),
|
||||
psess,
|
||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden },
|
||||
allow_expr_metavar,
|
||||
) {
|
||||
Ok(p) => return Some(ArgParser::List(p)),
|
||||
Err(e) => {
|
||||
@@ -147,9 +149,15 @@ pub fn from_attr_args<'sess>(
|
||||
}
|
||||
|
||||
Self::List(
|
||||
MetaItemListParser::new(&args.tokens, args.dspan.entire(), psess, should_emit)
|
||||
.map_err(|e| should_emit.emit_err(e))
|
||||
.ok()?,
|
||||
MetaItemListParser::new(
|
||||
&args.tokens,
|
||||
args.dspan.entire(),
|
||||
psess,
|
||||
should_emit,
|
||||
allow_expr_metavar,
|
||||
)
|
||||
.map_err(|e| should_emit.emit_err(e))
|
||||
.ok()?,
|
||||
)
|
||||
}
|
||||
AttrArgs::Eq { eq_span, expr } => Self::NameValue(NameValueParser {
|
||||
@@ -217,8 +225,9 @@ impl MetaItemOrLitParser {
|
||||
pub fn parse_single<'sess>(
|
||||
parser: &mut Parser<'sess>,
|
||||
should_emit: ShouldEmit,
|
||||
allow_expr_metavar: AllowExprMetavar,
|
||||
) -> PResult<'sess, MetaItemOrLitParser> {
|
||||
let mut this = MetaItemListParserContext { parser, should_emit };
|
||||
let mut this = MetaItemListParserContext { parser, should_emit, allow_expr_metavar };
|
||||
this.parse_meta_item_inner()
|
||||
}
|
||||
|
||||
@@ -390,7 +399,7 @@ fn expr_to_lit<'sess>(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if matches!(should_emit, ShouldEmit::Nothing) {
|
||||
if matches!(should_emit, ShouldEmit::Nothing) || matches!(expr.kind, ExprKind::Err(_)) {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
@@ -404,9 +413,19 @@ fn expr_to_lit<'sess>(
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether expansions of `expr` metavariables from decrarative macros
|
||||
/// are permitted. Used when parsing meta items; currently, only `cfg` predicates
|
||||
/// enable this option
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub enum AllowExprMetavar {
|
||||
No,
|
||||
Yes,
|
||||
}
|
||||
|
||||
struct MetaItemListParserContext<'a, 'sess> {
|
||||
parser: &'a mut Parser<'sess>,
|
||||
should_emit: ShouldEmit,
|
||||
allow_expr_metavar: AllowExprMetavar,
|
||||
}
|
||||
|
||||
impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
|
||||
@@ -447,20 +466,44 @@ fn unsuffixed_meta_item_from_lit(
|
||||
Ok(lit)
|
||||
}
|
||||
|
||||
fn parse_attr_item(&mut self) -> PResult<'sess, MetaItemParser> {
|
||||
if let Some(MetaVarKind::Meta { has_meta_form }) = self.parser.token.is_metavar_seq() {
|
||||
return if has_meta_form {
|
||||
let attr_item = self
|
||||
.parser
|
||||
.eat_metavar_seq(MetaVarKind::Meta { has_meta_form: true }, |this| {
|
||||
MetaItemListParserContext { parser: this, should_emit: self.should_emit }
|
||||
.parse_attr_item()
|
||||
})
|
||||
.unwrap();
|
||||
Ok(attr_item)
|
||||
} else {
|
||||
self.parser.unexpected_any()
|
||||
};
|
||||
fn parse_meta_item(&mut self) -> PResult<'sess, MetaItemParser> {
|
||||
if let Some(metavar) = self.parser.token.is_metavar_seq() {
|
||||
match (metavar, self.allow_expr_metavar) {
|
||||
(kind @ MetaVarKind::Expr { .. }, AllowExprMetavar::Yes) => {
|
||||
return self
|
||||
.parser
|
||||
.eat_metavar_seq(kind, |this| {
|
||||
MetaItemListParserContext {
|
||||
parser: this,
|
||||
should_emit: self.should_emit,
|
||||
allow_expr_metavar: AllowExprMetavar::Yes,
|
||||
}
|
||||
.parse_meta_item()
|
||||
})
|
||||
.ok_or_else(|| {
|
||||
self.parser.unexpected_any::<core::convert::Infallible>().unwrap_err()
|
||||
});
|
||||
}
|
||||
(MetaVarKind::Meta { has_meta_form }, _) => {
|
||||
return if has_meta_form {
|
||||
let attr_item = self
|
||||
.parser
|
||||
.eat_metavar_seq(MetaVarKind::Meta { has_meta_form: true }, |this| {
|
||||
MetaItemListParserContext {
|
||||
parser: this,
|
||||
should_emit: self.should_emit,
|
||||
allow_expr_metavar: self.allow_expr_metavar,
|
||||
}
|
||||
.parse_meta_item()
|
||||
})
|
||||
.unwrap();
|
||||
Ok(attr_item)
|
||||
} else {
|
||||
self.parser.unexpected_any()
|
||||
};
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let path = self.parser.parse_path(PathStyle::Mod)?;
|
||||
@@ -469,8 +512,12 @@ fn parse_attr_item(&mut self) -> PResult<'sess, MetaItemParser> {
|
||||
let args = if self.parser.check(exp!(OpenParen)) {
|
||||
let start = self.parser.token.span;
|
||||
let (sub_parsers, _) = self.parser.parse_paren_comma_seq(|parser| {
|
||||
MetaItemListParserContext { parser, should_emit: self.should_emit }
|
||||
.parse_meta_item_inner()
|
||||
MetaItemListParserContext {
|
||||
parser,
|
||||
should_emit: self.should_emit,
|
||||
allow_expr_metavar: self.allow_expr_metavar,
|
||||
}
|
||||
.parse_meta_item_inner()
|
||||
})?;
|
||||
let end = self.parser.prev_token.span;
|
||||
ArgParser::List(MetaItemListParser { sub_parsers, span: start.with_hi(end.hi()) })
|
||||
@@ -492,7 +539,7 @@ fn parse_meta_item_inner(&mut self) -> PResult<'sess, MetaItemOrLitParser> {
|
||||
Ok(MetaItemOrLitParser::Lit(self.unsuffixed_meta_item_from_lit(token_lit)?))
|
||||
} else {
|
||||
let prev_pros = self.parser.approx_token_stream_pos();
|
||||
match self.parse_attr_item() {
|
||||
match self.parse_meta_item() {
|
||||
Ok(item) => Ok(MetaItemOrLitParser::MetaItemParser(item)),
|
||||
Err(err) => {
|
||||
// If `parse_attr_item` made any progress, it likely has a more precise error we should prefer
|
||||
@@ -580,13 +627,15 @@ fn parse(
|
||||
psess: &'sess ParseSess,
|
||||
span: Span,
|
||||
should_emit: ShouldEmit,
|
||||
allow_expr_metavar: AllowExprMetavar,
|
||||
) -> PResult<'sess, MetaItemListParser> {
|
||||
let mut parser = Parser::new(psess, tokens, None);
|
||||
if let ShouldEmit::ErrorsAndLints { recovery } = should_emit {
|
||||
parser = parser.recovery(recovery);
|
||||
}
|
||||
|
||||
let mut this = MetaItemListParserContext { parser: &mut parser, should_emit };
|
||||
let mut this =
|
||||
MetaItemListParserContext { parser: &mut parser, should_emit, allow_expr_metavar };
|
||||
|
||||
// Presumably, the majority of the time there will only be one attr.
|
||||
let mut sub_parsers = ThinVec::with_capacity(1);
|
||||
@@ -618,8 +667,15 @@ pub(crate) fn new<'sess>(
|
||||
span: Span,
|
||||
psess: &'sess ParseSess,
|
||||
should_emit: ShouldEmit,
|
||||
allow_expr_metavar: AllowExprMetavar,
|
||||
) -> Result<Self, Diag<'sess>> {
|
||||
MetaItemListParserContext::parse(tokens.clone(), psess, span, should_emit)
|
||||
MetaItemListParserContext::parse(
|
||||
tokens.clone(),
|
||||
psess,
|
||||
span,
|
||||
should_emit,
|
||||
allow_expr_metavar,
|
||||
)
|
||||
}
|
||||
|
||||
/// Lets you pick and choose as what you want to parse each element in the list
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
};
|
||||
use rustc_feature::AttributeTemplate;
|
||||
use rustc_hir::AttrPath;
|
||||
use rustc_hir::attrs::{MirDialect, MirPhase};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_span::{Span, Symbol};
|
||||
use rustc_target::spec::TargetTuple;
|
||||
@@ -374,13 +375,6 @@ pub(crate) struct InvalidSince {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`soft` should not have any arguments")]
|
||||
pub(crate) struct SoftNoArgs {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("unknown version literal format, assuming it refers to a future version")]
|
||||
pub(crate) struct UnknownVersionLiteral {
|
||||
@@ -1030,3 +1024,36 @@ pub(crate) struct UnsupportedInstructionSet<'a> {
|
||||
pub instruction_set: Symbol,
|
||||
pub current_target: &'a TargetTuple,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("`dialect` key required")]
|
||||
pub(crate) struct CustomMirPhaseRequiresDialect {
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
#[label("`phase` argument requires a `dialect` argument")]
|
||||
pub phase_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("the {$dialect} dialect is not compatible with the {$phase} phase")]
|
||||
pub(crate) struct CustomMirIncompatibleDialectAndPhase {
|
||||
pub dialect: MirDialect,
|
||||
pub phase: MirPhase,
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
#[label("this dialect...")]
|
||||
pub dialect_span: Span,
|
||||
#[label("... is not compatible with this phase")]
|
||||
pub phase_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("can't mark as unstable using an already stable feature")]
|
||||
pub(crate) struct UnstableAttrForAlreadyStableFeature {
|
||||
#[primary_span]
|
||||
#[label("this feature is already stable")]
|
||||
#[help("consider removing the attribute")]
|
||||
pub attr_span: Span,
|
||||
#[label("the stability attribute annotates this item")]
|
||||
pub item_span: Span,
|
||||
}
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use rustc_ast::AttrStyle;
|
||||
use rustc_errors::DiagArgValue;
|
||||
use rustc_errors::{DiagArgValue, MultiSpan, StashKey};
|
||||
use rustc_feature::Features;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_hir::{MethodKind, Target};
|
||||
use rustc_span::sym;
|
||||
use rustc_hir::{AttrItem, Attribute, MethodKind, Target};
|
||||
use rustc_span::{BytePos, Span, Symbol, sym};
|
||||
|
||||
use crate::AttributeParser;
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::errors::{
|
||||
InvalidAttrAtCrateLevel, ItemFollowingInnerAttr, UnsupportedAttributesInWhere,
|
||||
};
|
||||
use crate::session_diagnostics::InvalidTarget;
|
||||
use crate::target_checking::Policy::Allow;
|
||||
|
||||
@@ -96,6 +100,25 @@ pub(crate) fn check_target(
|
||||
return;
|
||||
}
|
||||
|
||||
if matches!(cx.attr_path.segments.as_ref(), [sym::repr]) && target == Target::Crate {
|
||||
// The allowed targets of `repr` depend on its arguments. They can't be checked using
|
||||
// the `AttributeParser` code.
|
||||
let span = cx.attr_span;
|
||||
let item =
|
||||
cx.cx.first_line_of_next_item(span).map(|span| ItemFollowingInnerAttr { span });
|
||||
|
||||
let pound_to_opening_bracket = cx.attr_span.until(cx.inner_span);
|
||||
|
||||
cx.dcx()
|
||||
.create_err(InvalidAttrAtCrateLevel {
|
||||
span,
|
||||
pound_to_opening_bracket,
|
||||
name: sym::repr,
|
||||
item,
|
||||
})
|
||||
.emit();
|
||||
}
|
||||
|
||||
match allowed_targets.is_allowed(target) {
|
||||
AllowedResult::Allowed => {}
|
||||
AllowedResult::Warn => {
|
||||
@@ -163,6 +186,113 @@ pub(crate) fn check_crate_level(target: Target, cx: &mut AcceptContext<'_, 'sess
|
||||
|
||||
cx.emit_lint(rustc_session::lint::builtin::UNUSED_ATTRIBUTES, kind, attr_span);
|
||||
}
|
||||
|
||||
// FIXME: Fix "Cannot determine resolution" error and remove built-in macros
|
||||
// from this check.
|
||||
pub(crate) fn check_invalid_crate_level_attr_item(&self, attr: &AttrItem, inner_span: Span) {
|
||||
// Check for builtin attributes at the crate level
|
||||
// which were unsuccessfully resolved due to cannot determine
|
||||
// resolution for the attribute macro error.
|
||||
const ATTRS_TO_CHECK: &[Symbol] =
|
||||
&[sym::derive, sym::test, sym::test_case, sym::global_allocator, sym::bench];
|
||||
|
||||
// FIXME(jdonszelmann): all attrs should be combined here cleaning this up some day.
|
||||
if let Some(name) = ATTRS_TO_CHECK.iter().find(|attr_to_check| matches!(attr.path.segments.as_ref(), [segment] if segment == *attr_to_check)) {
|
||||
let span = attr.span;
|
||||
let name = *name;
|
||||
|
||||
let item = self.first_line_of_next_item(span).map(|span| ItemFollowingInnerAttr { span });
|
||||
|
||||
let err = self.dcx().create_err(InvalidAttrAtCrateLevel {
|
||||
span,
|
||||
pound_to_opening_bracket: span.until(inner_span),
|
||||
name,
|
||||
item,
|
||||
});
|
||||
|
||||
self.dcx().try_steal_replace_and_emit_err(
|
||||
attr.path.span,
|
||||
StashKey::UndeterminedMacroResolution,
|
||||
err,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn first_line_of_next_item(&self, span: Span) -> Option<Span> {
|
||||
// We can't exactly call `tcx.hir_free_items()` here because it's too early and querying
|
||||
// this would create a circular dependency. Instead, we resort to getting the original
|
||||
// source code that follows `span` and find the next item from here.
|
||||
|
||||
self.sess()
|
||||
.source_map()
|
||||
.span_to_source(span, |content, _, span_end| {
|
||||
let mut source = &content[span_end..];
|
||||
let initial_source_len = source.len();
|
||||
let span = try {
|
||||
loop {
|
||||
let first = source.chars().next()?;
|
||||
|
||||
if first.is_whitespace() {
|
||||
let split_idx = source.find(|c: char| !c.is_whitespace())?;
|
||||
source = &source[split_idx..];
|
||||
} else if source.starts_with("//") {
|
||||
let line_idx = source.find('\n')?;
|
||||
source = &source[line_idx + '\n'.len_utf8()..];
|
||||
} else if source.starts_with("/*") {
|
||||
// FIXME: support nested comments.
|
||||
let close_idx = source.find("*/")?;
|
||||
source = &source[close_idx + "*/".len()..];
|
||||
} else if first == '#' {
|
||||
// FIXME: properly find the end of the attributes in order to accurately
|
||||
// skip them. This version just consumes the source code until the next
|
||||
// `]`.
|
||||
let close_idx = source.find(']')?;
|
||||
source = &source[close_idx + ']'.len_utf8()..];
|
||||
} else {
|
||||
let lo = span_end + initial_source_len - source.len();
|
||||
let last_line = source.split('\n').next().map(|s| s.trim_end())?;
|
||||
|
||||
let hi = lo + last_line.len();
|
||||
let lo = BytePos(lo as u32);
|
||||
let hi = BytePos(hi as u32);
|
||||
let next_item_span = Span::new(lo, hi, span.ctxt(), None);
|
||||
|
||||
break next_item_span;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(span)
|
||||
})
|
||||
.ok()
|
||||
.flatten()
|
||||
}
|
||||
|
||||
pub(crate) fn check_invalid_where_predicate_attrs<'attr>(
|
||||
&self,
|
||||
attrs: impl IntoIterator<Item = &'attr Attribute>,
|
||||
) {
|
||||
// FIXME(where_clause_attrs): Currently, as the following check shows,
|
||||
// only `#[cfg]` and `#[cfg_attr]` are allowed, but it should be removed
|
||||
// if we allow more attributes (e.g., tool attributes and `allow/deny/warn`)
|
||||
// in where clauses. After that, this function would become useless.
|
||||
let spans = attrs
|
||||
.into_iter()
|
||||
// FIXME: We shouldn't need to special-case `doc`!
|
||||
.filter(|attr| {
|
||||
matches!(
|
||||
attr,
|
||||
Attribute::Parsed(AttributeKind::DocComment { .. } | AttributeKind::Doc(_))
|
||||
| Attribute::Unparsed(_)
|
||||
)
|
||||
})
|
||||
.map(|attr| attr.span())
|
||||
.collect::<Vec<_>>();
|
||||
if !spans.is_empty() {
|
||||
self.dcx()
|
||||
.emit_err(UnsupportedAttributesInWhere { span: MultiSpan::from_spans(spans) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Takes a list of `allowed_targets` for an attribute, and the `target` the attribute was applied to.
|
||||
|
||||
@@ -324,18 +324,23 @@ pub(crate) fn cannot_act_on_moved_value(
|
||||
verb: &str,
|
||||
optional_adverb_for_moved: &str,
|
||||
moved_path: Option<String>,
|
||||
primary_message: Option<String>,
|
||||
) -> Diag<'infcx> {
|
||||
let moved_path = moved_path.map(|mp| format!(": `{mp}`")).unwrap_or_default();
|
||||
if let Some(primary_message) = primary_message {
|
||||
struct_span_code_err!(self.dcx(), use_span, E0382, "{}", primary_message)
|
||||
} else {
|
||||
let moved_path = moved_path.map(|mp| format!(": `{mp}`")).unwrap_or_default();
|
||||
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
use_span,
|
||||
E0382,
|
||||
"{} of {}moved value{}",
|
||||
verb,
|
||||
optional_adverb_for_moved,
|
||||
moved_path,
|
||||
)
|
||||
struct_span_code_err!(
|
||||
self.dcx(),
|
||||
use_span,
|
||||
E0382,
|
||||
"{} of {}moved value{}",
|
||||
verb,
|
||||
optional_adverb_for_moved,
|
||||
moved_path,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn cannot_borrow_path_as_mutable_because(
|
||||
|
||||
@@ -6,12 +6,16 @@
|
||||
use either::Either;
|
||||
use hir::{ClosureKind, Path};
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_data_structures::thin_vec::ThinVec;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{Applicability, Diag, MultiSpan, struct_span_code_err};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::attrs::diagnostic::FormatArgs;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::intravisit::{Visitor, walk_block, walk_expr};
|
||||
use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, LangItem, PatField};
|
||||
use rustc_hir::{
|
||||
CoroutineDesugaring, CoroutineKind, CoroutineSource, LangItem, PatField, find_attr,
|
||||
};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::hir::nested_filter::OnlyBodies;
|
||||
use rustc_middle::mir::{
|
||||
@@ -138,6 +142,36 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
|
||||
let partial_str = if is_partial_move { "partial " } else { "" };
|
||||
let partially_str = if is_partial_move { "partially " } else { "" };
|
||||
|
||||
let (on_move_message, on_move_label, on_move_notes) = if let ty::Adt(item_def, args) =
|
||||
self.body.local_decls[moved_place.local].ty.kind()
|
||||
&& let Some(Some(directive)) = find_attr!(self.infcx.tcx, item_def.did(), OnMove { directive, .. } => directive)
|
||||
{
|
||||
let item_name = self.infcx.tcx.item_name(item_def.did()).to_string();
|
||||
let mut generic_args: Vec<_> = self
|
||||
.infcx
|
||||
.tcx
|
||||
.generics_of(item_def.did())
|
||||
.own_params
|
||||
.iter()
|
||||
.filter_map(|param| Some((param.name, args[param.index as usize].to_string())))
|
||||
.collect();
|
||||
generic_args.push((kw::SelfUpper, item_name));
|
||||
|
||||
let args = FormatArgs {
|
||||
this: String::new(),
|
||||
trait_sugared: String::new(),
|
||||
item_context: "",
|
||||
generic_args,
|
||||
};
|
||||
(
|
||||
directive.message.as_ref().map(|e| e.1.format(&args)),
|
||||
directive.label.as_ref().map(|e| e.1.format(&args)),
|
||||
directive.notes.iter().map(|e| e.format(&args)).collect(),
|
||||
)
|
||||
} else {
|
||||
(None, None, ThinVec::new())
|
||||
};
|
||||
|
||||
let mut err = self.cannot_act_on_moved_value(
|
||||
span,
|
||||
desired_action.as_noun(),
|
||||
@@ -146,8 +180,13 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
|
||||
moved_place,
|
||||
DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
|
||||
),
|
||||
on_move_message,
|
||||
);
|
||||
|
||||
for note in on_move_notes {
|
||||
err.note(note);
|
||||
}
|
||||
|
||||
let reinit_spans = maybe_reinitialized_locations
|
||||
.iter()
|
||||
.take(3)
|
||||
@@ -275,12 +314,16 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
|
||||
if needs_note {
|
||||
if let Some(local) = place.as_local() {
|
||||
let span = self.body.local_decls[local].source_info.span;
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move,
|
||||
ty,
|
||||
place: ¬e_msg,
|
||||
span,
|
||||
});
|
||||
if let Some(on_move_label) = on_move_label {
|
||||
err.span_label(span, on_move_label);
|
||||
} else {
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move,
|
||||
ty,
|
||||
place: ¬e_msg,
|
||||
span,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Note {
|
||||
is_partial_move,
|
||||
@@ -545,8 +588,6 @@ fn visit_pat(&mut self, p: &'hir hir::Pat<'hir>) {
|
||||
}
|
||||
|
||||
// for dbg!(x) which may take ownership, suggest dbg!(&x) instead
|
||||
// but here we actually do not check whether the macro name is `dbg!`
|
||||
// so that we may extend the scope a bit larger to cover more cases
|
||||
fn suggest_ref_for_dbg_args(
|
||||
&self,
|
||||
body: &hir::Expr<'_>,
|
||||
@@ -560,29 +601,41 @@ fn suggest_ref_for_dbg_args(
|
||||
});
|
||||
let Some(var_info) = var_info else { return };
|
||||
let arg_name = var_info.name;
|
||||
struct MatchArgFinder {
|
||||
expr_span: Span,
|
||||
match_arg_span: Option<Span>,
|
||||
struct MatchArgFinder<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
move_span: Span,
|
||||
arg_name: Symbol,
|
||||
match_arg_span: Option<Span> = None,
|
||||
}
|
||||
impl Visitor<'_> for MatchArgFinder {
|
||||
impl Visitor<'_> for MatchArgFinder<'_> {
|
||||
fn visit_expr(&mut self, e: &hir::Expr<'_>) {
|
||||
// dbg! is expanded into a match pattern, we need to find the right argument span
|
||||
if let hir::ExprKind::Match(expr, ..) = &e.kind
|
||||
&& let hir::ExprKind::Path(hir::QPath::Resolved(
|
||||
_,
|
||||
path @ Path { segments: [seg], .. },
|
||||
)) = &expr.kind
|
||||
&& seg.ident.name == self.arg_name
|
||||
&& self.expr_span.source_callsite().contains(expr.span)
|
||||
if let hir::ExprKind::Match(scrutinee, ..) = &e.kind
|
||||
&& let hir::ExprKind::Tup(args) = scrutinee.kind
|
||||
&& e.span.macro_backtrace().any(|expn| {
|
||||
expn.macro_def_id.is_some_and(|macro_def_id| {
|
||||
self.tcx.is_diagnostic_item(sym::dbg_macro, macro_def_id)
|
||||
})
|
||||
})
|
||||
{
|
||||
self.match_arg_span = Some(path.span);
|
||||
for arg in args {
|
||||
if let hir::ExprKind::Path(hir::QPath::Resolved(
|
||||
_,
|
||||
path @ Path { segments: [seg], .. },
|
||||
)) = &arg.kind
|
||||
&& seg.ident.name == self.arg_name
|
||||
&& self.move_span.source_equal(arg.span)
|
||||
{
|
||||
self.match_arg_span = Some(path.span);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
hir::intravisit::walk_expr(self, e);
|
||||
}
|
||||
}
|
||||
|
||||
let mut finder = MatchArgFinder { expr_span: move_span, match_arg_span: None, arg_name };
|
||||
let mut finder = MatchArgFinder { tcx: self.infcx.tcx, move_span, arg_name, .. };
|
||||
finder.visit_expr(body);
|
||||
if let Some(macro_arg_span) = finder.match_arg_span {
|
||||
err.span_suggestion_verbose(
|
||||
@@ -1526,10 +1579,8 @@ fn suggest_adding_bounds(&self, err: &mut Diag<'_>, ty: Ty<'tcx>, def_id: DefId,
|
||||
let tcx = self.infcx.tcx;
|
||||
let generics = tcx.generics_of(self.mir_def_id());
|
||||
|
||||
let Some(hir_generics) = tcx
|
||||
.typeck_root_def_id(self.mir_def_id().to_def_id())
|
||||
.as_local()
|
||||
.and_then(|def_id| tcx.hir_get_generics(def_id))
|
||||
let Some(hir_generics) =
|
||||
tcx.hir_get_generics(tcx.typeck_root_def_id_local(self.mir_def_id()))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -23,8 +23,7 @@
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult, MoveOutIndex};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
|
||||
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Spanned, Symbol, sym};
|
||||
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
||||
use rustc_trait_selection::error_reporting::traits::call_kind::{CallDesugaringKind, call_kind};
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
@@ -1275,12 +1274,9 @@ fn explain_captures(
|
||||
if let ty::Param(param_ty) = *self_ty.kind()
|
||||
&& let generics = self.infcx.tcx.generics_of(self.mir_def_id())
|
||||
&& let param = generics.type_param(param_ty, self.infcx.tcx)
|
||||
&& let Some(hir_generics) = self
|
||||
.infcx
|
||||
.tcx
|
||||
.typeck_root_def_id(self.mir_def_id().to_def_id())
|
||||
.as_local()
|
||||
.and_then(|def_id| self.infcx.tcx.hir_get_generics(def_id))
|
||||
&& let Some(hir_generics) = self.infcx.tcx.hir_get_generics(
|
||||
self.infcx.tcx.typeck_root_def_id_local(self.mir_def_id()),
|
||||
)
|
||||
&& let spans = hir_generics
|
||||
.predicates
|
||||
.iter()
|
||||
@@ -1378,7 +1374,9 @@ fn explain_captures(
|
||||
matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
|
||||
});
|
||||
if is_option_or_result && maybe_reinitialized_locations_is_empty {
|
||||
err.subdiagnostic(CaptureReasonLabel::BorrowContent { var_span });
|
||||
err.subdiagnostic(CaptureReasonLabel::BorrowContent {
|
||||
var_span: var_span.shrink_to_hi(),
|
||||
});
|
||||
}
|
||||
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
|
||||
let ty = moved_place.ty(self.body, tcx).ty;
|
||||
|
||||
@@ -990,30 +990,25 @@ fn add_move_error_details(
|
||||
let bind_to = &self.body.local_decls[*local];
|
||||
let binding_span = bind_to.source_info.span;
|
||||
|
||||
if j == 0 {
|
||||
err.span_label(binding_span, "data moved here");
|
||||
} else {
|
||||
err.span_label(binding_span, "...and here");
|
||||
}
|
||||
|
||||
if binds_to.len() == 1 {
|
||||
let place_desc = self.local_name(*local).map(|sym| format!("`{sym}`"));
|
||||
|
||||
if !desugar_spans.contains(&binding_span)
|
||||
&& let Some(expr) = self.find_expr(binding_span)
|
||||
{
|
||||
// The binding_span doesn't correspond to a let binding desugaring
|
||||
// and is an expression where calling `.clone()` would be valid.
|
||||
let local_place: PlaceRef<'tcx> = (*local).into();
|
||||
self.suggest_cloning(err, local_place, bind_to.ty, expr, None);
|
||||
}
|
||||
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
|
||||
is_partial_move: false,
|
||||
err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::LabelMovedHere {
|
||||
ty: bind_to.ty,
|
||||
place: place_desc.as_deref().unwrap_or("the place"),
|
||||
span: binding_span,
|
||||
});
|
||||
|
||||
if !desugar_spans.contains(&binding_span)
|
||||
&& let Some(expr) = self.find_expr(binding_span)
|
||||
{
|
||||
let local_place: PlaceRef<'tcx> = (*local).into();
|
||||
self.suggest_cloning(err, local_place, bind_to.ty, expr, None);
|
||||
}
|
||||
} else if j == 0 {
|
||||
err.span_label(binding_span, "data moved here");
|
||||
} else {
|
||||
err.span_label(binding_span, "...and here");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -372,6 +372,119 @@ fn give_name_from_error_region(&self, fr: RegionVid) -> Option<RegionName> {
|
||||
}
|
||||
}
|
||||
|
||||
/// For closure/coroutine upvar regions, attempts to find a named lifetime
|
||||
/// from the parent function's signature that corresponds to the anonymous
|
||||
/// region `fr`. This handles cases where a parent function's named lifetime
|
||||
/// (like `'a`) appears in a captured variable's type but gets assigned a
|
||||
/// separate `RegionVid` without an `external_name` during region renumbering.
|
||||
///
|
||||
/// Works by getting the parent function's parameter type (with real named
|
||||
/// lifetimes via `liberate_late_bound_regions`), then structurally walking
|
||||
/// both the parent's parameter type and the closure's upvar type to find
|
||||
/// where `fr` appears and what named lifetime is at the same position.
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn give_name_if_we_can_match_upvar_args(
|
||||
&self,
|
||||
fr: RegionVid,
|
||||
upvar_index: usize,
|
||||
) -> Option<RegionName> {
|
||||
let tcx = self.infcx.tcx;
|
||||
let defining_ty = self.regioncx.universal_regions().defining_ty;
|
||||
|
||||
let closure_def_id = match defining_ty {
|
||||
DefiningTy::Closure(def_id, _)
|
||||
| DefiningTy::Coroutine(def_id, _)
|
||||
| DefiningTy::CoroutineClosure(def_id, _) => def_id,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
let parent_def_id = tcx.parent(closure_def_id);
|
||||
|
||||
// Only works if the parent is a function with a fn_sig.
|
||||
if !matches!(tcx.def_kind(parent_def_id), DefKind::Fn | DefKind::AssocFn) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Find which parameter index this upvar corresponds to by matching
|
||||
// the captured variable's HirId against the parent's parameter patterns.
|
||||
// This only matches simple bindings (not destructuring patterns) and
|
||||
// only when the upvar is a direct parameter (not a local variable).
|
||||
let captured_place = self.upvars.get(upvar_index)?;
|
||||
let upvar_hir_id = captured_place.get_root_variable();
|
||||
let parent_local_def_id = parent_def_id.as_local()?;
|
||||
let parent_body = tcx.hir_body_owned_by(parent_local_def_id);
|
||||
let param_index =
|
||||
parent_body.params.iter().position(|param| param.pat.hir_id == upvar_hir_id)?;
|
||||
|
||||
// Get the parent fn's signature with liberated late-bound regions,
|
||||
// so we have `ReLateParam` instead of `ReBound`.
|
||||
let parent_fn_sig = tcx.fn_sig(parent_def_id).instantiate_identity();
|
||||
let liberated_sig = tcx.liberate_late_bound_regions(parent_def_id, parent_fn_sig);
|
||||
let parent_param_ty = *liberated_sig.inputs().get(param_index)?;
|
||||
|
||||
// Get the upvar's NLL type (with ReVar regions from renumbering).
|
||||
let upvar_nll_ty = *defining_ty.upvar_tys().get(upvar_index)?;
|
||||
|
||||
debug!(
|
||||
"give_name_if_we_can_match_upvar_args: parent_param_ty={:?}, upvar_nll_ty={:?}",
|
||||
parent_param_ty, upvar_nll_ty
|
||||
);
|
||||
|
||||
// Collect free regions from both types in structural order.
|
||||
// This only works when both types have the same structure, i.e.
|
||||
// the upvar captures the whole variable, not a partial place like
|
||||
// `x.field`. Bail out if the region counts differ, since that means
|
||||
// the types diverged and positional correspondence is unreliable.
|
||||
let mut parent_regions = vec![];
|
||||
tcx.for_each_free_region(&parent_param_ty, |r| parent_regions.push(r));
|
||||
|
||||
let mut nll_regions = vec![];
|
||||
tcx.for_each_free_region(&upvar_nll_ty, |r| nll_regions.push(r));
|
||||
|
||||
if parent_regions.len() != nll_regions.len() {
|
||||
debug!(
|
||||
"give_name_if_we_can_match_upvar_args: region count mismatch ({} vs {})",
|
||||
parent_regions.len(),
|
||||
nll_regions.len()
|
||||
);
|
||||
return None;
|
||||
}
|
||||
|
||||
for (parent_r, nll_r) in iter::zip(&parent_regions, &nll_regions) {
|
||||
if nll_r.as_var() == fr {
|
||||
match parent_r.kind() {
|
||||
ty::ReLateParam(late_param) => {
|
||||
if let Some(name) = late_param.kind.get_name(tcx) {
|
||||
let span = late_param
|
||||
.kind
|
||||
.get_id()
|
||||
.and_then(|id| tcx.hir_span_if_local(id))
|
||||
.unwrap_or(DUMMY_SP);
|
||||
return Some(RegionName {
|
||||
name,
|
||||
source: RegionNameSource::NamedLateParamRegion(span),
|
||||
});
|
||||
}
|
||||
}
|
||||
ty::ReEarlyParam(ebr) => {
|
||||
if ebr.is_named() {
|
||||
let def_id =
|
||||
tcx.generics_of(parent_def_id).region_param(ebr, tcx).def_id;
|
||||
let span = tcx.hir_span_if_local(def_id).unwrap_or(DUMMY_SP);
|
||||
return Some(RegionName {
|
||||
name: ebr.name,
|
||||
source: RegionNameSource::NamedEarlyParamRegion(span),
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Finds an argument that contains `fr` and label it with a fully
|
||||
/// elaborated type, returning something like `'1`. Result looks
|
||||
/// like:
|
||||
@@ -644,6 +757,13 @@ fn try_match_adt_and_generic_args<'hir>(
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn give_name_if_anonymous_region_appears_in_upvars(&self, fr: RegionVid) -> Option<RegionName> {
|
||||
let upvar_index = self.regioncx.get_upvar_index_for_region(self.infcx.tcx, fr)?;
|
||||
|
||||
// Before synthesizing an anonymous name like `'1`, try to find a
|
||||
// named lifetime from the parent function's signature that matches.
|
||||
if let Some(region_name) = self.give_name_if_we_can_match_upvar_args(fr, upvar_index) {
|
||||
return Some(region_name);
|
||||
}
|
||||
|
||||
let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region(
|
||||
self.infcx.tcx,
|
||||
self.upvars,
|
||||
|
||||
@@ -456,7 +456,18 @@ pub(crate) enum CaptureReasonLabel<'a> {
|
||||
is_move_msg: bool,
|
||||
is_loop_message: bool,
|
||||
},
|
||||
#[label("help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents")]
|
||||
#[suggestion(
|
||||
"consider calling `.as_ref()` to borrow the value's contents",
|
||||
applicability = "maybe-incorrect",
|
||||
code = ".as_ref()",
|
||||
style = "verbose"
|
||||
)]
|
||||
#[suggestion(
|
||||
"consider calling `.as_mut()` to mutably borrow the value's contents",
|
||||
applicability = "maybe-incorrect",
|
||||
code = ".as_mut()",
|
||||
style = "verbose"
|
||||
)]
|
||||
BorrowContent {
|
||||
#[primary_span]
|
||||
var_span: Span,
|
||||
@@ -570,6 +581,16 @@ pub(crate) enum TypeNoCopy<'a, 'tcx> {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[label(
|
||||
"data moved here because {$place} has type `{$ty}`, which does not implement the `Copy` \
|
||||
trait"
|
||||
)]
|
||||
LabelMovedHere {
|
||||
ty: Ty<'tcx>,
|
||||
place: &'a str,
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[note(
|
||||
"{$is_partial_move ->
|
||||
[true] partial move
|
||||
|
||||
@@ -32,8 +32,7 @@
|
||||
use rustc_mir_dataflow::move_paths::MoveData;
|
||||
use rustc_mir_dataflow::points::DenseLocationMap;
|
||||
use rustc_span::def_id::CRATE_DEF_ID;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::{Span, sym};
|
||||
use rustc_span::{Span, Spanned, sym};
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints;
|
||||
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
|
||||
@@ -375,10 +374,6 @@ fn body(&self) -> &Body<'tcx> {
|
||||
self.body
|
||||
}
|
||||
|
||||
fn unsized_feature_enabled(&self) -> bool {
|
||||
self.tcx().features().unsized_fn_params()
|
||||
}
|
||||
|
||||
/// Equate the inferred type and the annotated type for user type annotations
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn check_user_type_annotations(&mut self) {
|
||||
@@ -661,7 +656,7 @@ fn visit_statement(&mut self, stmt: &Statement<'tcx>, location: Location) {
|
||||
);
|
||||
}
|
||||
|
||||
if !self.unsized_feature_enabled() {
|
||||
if !self.tcx().features().unsized_fn_params() {
|
||||
let trait_ref = ty::TraitRef::new(
|
||||
tcx,
|
||||
tcx.require_lang_item(LangItem::Sized, self.last_span),
|
||||
@@ -937,9 +932,10 @@ fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
|
||||
}
|
||||
}
|
||||
|
||||
// When `unsized_fn_params` is enabled, only function calls
|
||||
// and nullary ops are checked in `check_call_dest`.
|
||||
if !self.unsized_feature_enabled() {
|
||||
// When `unsized_fn_params` is enabled, this is checked in `check_call_dest`,
|
||||
// and `hir_typeck` still forces all non-argument locals to be sized (i.e., we don't
|
||||
// fully re-check what was already checked on HIR).
|
||||
if !self.tcx().features().unsized_fn_params() {
|
||||
match self.body.local_kind(local) {
|
||||
LocalKind::ReturnPointer | LocalKind::Arg => {
|
||||
// return values of normal functions are required to be
|
||||
@@ -1954,8 +1950,8 @@ fn check_call_dest(
|
||||
}
|
||||
|
||||
// When `unsized_fn_params` is not enabled,
|
||||
// this check is done at `check_local`.
|
||||
if self.unsized_feature_enabled() {
|
||||
// this check is done at `visit_local_decl`.
|
||||
if self.tcx().features().unsized_fn_params() {
|
||||
let span = term.source_info.span;
|
||||
self.ensure_place_sized(dest_ty, span);
|
||||
}
|
||||
|
||||
@@ -476,12 +476,10 @@ fn build(self) -> UniversalRegions<'tcx> {
|
||||
let mut indices = self.compute_indices(fr_static, defining_ty);
|
||||
debug!("build: indices={:?}", indices);
|
||||
|
||||
let typeck_root_def_id = self.infcx.tcx.typeck_root_def_id(self.mir_def.to_def_id());
|
||||
|
||||
// If this is a 'root' body (not a closure/coroutine/inline const), then
|
||||
// there are no extern regions, so the local regions start at the same
|
||||
// position as the (empty) sub-list of extern regions
|
||||
let first_local_index = if self.mir_def.to_def_id() == typeck_root_def_id {
|
||||
let first_local_index = if !self.infcx.tcx.is_typeck_child(self.mir_def.to_def_id()) {
|
||||
first_extern_index
|
||||
} else {
|
||||
// If this is a closure, coroutine, or inline-const, then the late-bound regions from the enclosing
|
||||
@@ -583,7 +581,7 @@ fn build(self) -> UniversalRegions<'tcx> {
|
||||
/// see `DefiningTy` for details.
|
||||
fn defining_ty(&self) -> DefiningTy<'tcx> {
|
||||
let tcx = self.infcx.tcx;
|
||||
let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.to_def_id());
|
||||
let typeck_root_def_id = tcx.typeck_root_def_id_local(self.mir_def);
|
||||
|
||||
match tcx.hir_body_owner_kind(self.mir_def) {
|
||||
BodyOwnerKind::Closure | BodyOwnerKind::Fn => {
|
||||
@@ -614,7 +612,7 @@ fn defining_ty(&self) -> DefiningTy<'tcx> {
|
||||
|
||||
BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(..) => {
|
||||
let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id);
|
||||
if self.mir_def.to_def_id() == typeck_root_def_id {
|
||||
if self.mir_def == typeck_root_def_id {
|
||||
let args = self.infcx.replace_free_regions_with_nll_infer_vars(
|
||||
NllRegionVariableOrigin::FreeRegion,
|
||||
identity_args,
|
||||
@@ -660,7 +658,7 @@ fn compute_indices(
|
||||
defining_ty: DefiningTy<'tcx>,
|
||||
) -> UniversalRegionIndices<'tcx> {
|
||||
let tcx = self.infcx.tcx;
|
||||
let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.to_def_id());
|
||||
let typeck_root_def_id = tcx.typeck_root_def_id_local(self.mir_def);
|
||||
let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id);
|
||||
let renumbered_args = defining_ty.args();
|
||||
|
||||
@@ -948,16 +946,14 @@ fn for_each_late_bound_region_in_recursive_scope<'tcx>(
|
||||
mut mir_def_id: LocalDefId,
|
||||
mut f: impl FnMut(ty::Region<'tcx>),
|
||||
) {
|
||||
let typeck_root_def_id = tcx.typeck_root_def_id(mir_def_id.to_def_id());
|
||||
|
||||
// Walk up the tree, collecting late-bound regions until we hit the typeck root
|
||||
loop {
|
||||
for_each_late_bound_region_in_item(tcx, mir_def_id, &mut f);
|
||||
|
||||
if mir_def_id.to_def_id() == typeck_root_def_id {
|
||||
break;
|
||||
} else {
|
||||
if tcx.is_typeck_child(mir_def_id.to_def_id()) {
|
||||
mir_def_id = tcx.local_parent(mir_def_id);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ mod llvm_enzyme {
|
||||
};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_hir::attrs::RustcAutodiff;
|
||||
use rustc_span::{Ident, Span, Symbol, sym};
|
||||
use rustc_span::{Ident, Span, Symbol, kw, sym};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
use tracing::{debug, trace};
|
||||
|
||||
@@ -197,7 +197,7 @@ pub(crate) fn expand_reverse(
|
||||
/// }
|
||||
/// #[rustc_autodiff(Reverse, Duplicated, Active)]
|
||||
/// fn cos_box(x: &Box<f32>, dx: &mut Box<f32>, dret: f32) -> f32 {
|
||||
/// std::intrinsics::autodiff(sin::<>, cos_box::<>, (x, dx, dret))
|
||||
/// std::intrinsics::autodiff(sin::<> as fn(..) -> .., cos_box::<>, (x, dx, dret))
|
||||
/// }
|
||||
/// ```
|
||||
/// FIXME(ZuseZ4): Once autodiff is enabled by default, make this a doc comment which is checked
|
||||
@@ -224,16 +224,18 @@ pub(crate) fn expand_with_mode(
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
Annotatable::AssocItem(assoc_item, Impl { of_trait: _ }) => match &assoc_item.kind {
|
||||
ast::AssocItemKind::Fn(box ast::Fn { sig, ident, generics, .. }) => Some((
|
||||
assoc_item.vis.clone(),
|
||||
sig.clone(),
|
||||
ident.clone(),
|
||||
generics.clone(),
|
||||
true,
|
||||
)),
|
||||
_ => None,
|
||||
},
|
||||
Annotatable::AssocItem(assoc_item, _ctxt @ (Impl { of_trait: _ } | Trait)) => {
|
||||
match &assoc_item.kind {
|
||||
ast::AssocItemKind::Fn(box ast::Fn { sig, ident, generics, .. }) => Some((
|
||||
assoc_item.vis.clone(),
|
||||
sig.clone(),
|
||||
ident.clone(),
|
||||
generics.clone(),
|
||||
true,
|
||||
)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}) else {
|
||||
dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() });
|
||||
@@ -326,6 +328,7 @@ pub(crate) fn expand_with_mode(
|
||||
primal,
|
||||
first_ident(&meta_item_vec[0]),
|
||||
span,
|
||||
&sig,
|
||||
&d_sig,
|
||||
&generics,
|
||||
is_impl,
|
||||
@@ -392,14 +395,14 @@ fn same_attribute(attr: &ast::AttrKind, item: &ast::AttrKind) -> bool {
|
||||
}
|
||||
Annotatable::Item(iitem.clone())
|
||||
}
|
||||
Annotatable::AssocItem(ref mut assoc_item, i @ Impl { .. }) => {
|
||||
Annotatable::AssocItem(ref mut assoc_item, ctxt @ (Impl { .. } | Trait)) => {
|
||||
if !assoc_item.attrs.iter().any(|a| same_attribute(&a.kind, &attr.kind)) {
|
||||
assoc_item.attrs.push(attr);
|
||||
}
|
||||
if assoc_item.attrs.iter().any(|a| same_attribute(&a.kind, &inline_never.kind)) {
|
||||
has_inline_never = true;
|
||||
}
|
||||
Annotatable::AssocItem(assoc_item.clone(), i)
|
||||
Annotatable::AssocItem(assoc_item.clone(), ctxt)
|
||||
}
|
||||
Annotatable::Stmt(ref mut stmt) => {
|
||||
match stmt.kind {
|
||||
@@ -440,7 +443,7 @@ fn same_attribute(attr: &ast::AttrKind, item: &ast::AttrKind) -> bool {
|
||||
}
|
||||
|
||||
let d_annotatable = match &item {
|
||||
Annotatable::AssocItem(_, _) => {
|
||||
Annotatable::AssocItem(_, ctxt) => {
|
||||
let assoc_item: AssocItemKind = ast::AssocItemKind::Fn(d_fn);
|
||||
let d_fn = Box::new(ast::AssocItem {
|
||||
attrs: d_attrs,
|
||||
@@ -450,7 +453,7 @@ fn same_attribute(attr: &ast::AttrKind, item: &ast::AttrKind) -> bool {
|
||||
kind: assoc_item,
|
||||
tokens: None,
|
||||
});
|
||||
Annotatable::AssocItem(d_fn, Impl { of_trait: false })
|
||||
Annotatable::AssocItem(d_fn, *ctxt)
|
||||
}
|
||||
Annotatable::Item(_) => {
|
||||
let mut d_fn = ecx.item(span, d_attrs, ItemKind::Fn(d_fn));
|
||||
@@ -496,18 +499,62 @@ fn assure_mut_ref(ty: &ast::Ty) -> ast::Ty {
|
||||
|
||||
// Generate `autodiff` intrinsic call
|
||||
// ```
|
||||
// std::intrinsics::autodiff(source, diff, (args))
|
||||
// std::intrinsics::autodiff(source as fn(..) -> .., diff, (args))
|
||||
// ```
|
||||
fn call_autodiff(
|
||||
ecx: &ExtCtxt<'_>,
|
||||
primal: Ident,
|
||||
diff: Ident,
|
||||
span: Span,
|
||||
p_sig: &FnSig,
|
||||
d_sig: &FnSig,
|
||||
generics: &Generics,
|
||||
is_impl: bool,
|
||||
) -> rustc_ast::Stmt {
|
||||
let primal_path_expr = gen_turbofish_expr(ecx, primal, generics, span, is_impl);
|
||||
|
||||
let self_ty = || ecx.ty_path(ast::Path::from_ident(Ident::with_dummy_span(kw::SelfUpper)));
|
||||
let fn_ptr_params: ThinVec<ast::Param> = p_sig
|
||||
.decl
|
||||
.inputs
|
||||
.iter()
|
||||
.map(|param| {
|
||||
let ty = match ¶m.ty.kind {
|
||||
TyKind::ImplicitSelf => self_ty(),
|
||||
TyKind::Ref(lt, mt) if matches!(mt.ty.kind, TyKind::ImplicitSelf) => ecx.ty(
|
||||
span,
|
||||
TyKind::Ref(lt.clone(), ast::MutTy { ty: self_ty(), mutbl: mt.mutbl }),
|
||||
),
|
||||
TyKind::Ptr(mt) if matches!(mt.ty.kind, TyKind::ImplicitSelf) => {
|
||||
ecx.ty(span, TyKind::Ptr(ast::MutTy { ty: self_ty(), mutbl: mt.mutbl }))
|
||||
}
|
||||
_ => param.ty.clone(),
|
||||
};
|
||||
ast::Param {
|
||||
attrs: ast::AttrVec::new(),
|
||||
ty,
|
||||
pat: Box::new(ecx.pat_wild(span)),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span,
|
||||
is_placeholder: false,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let fn_ptr_ty = ecx.ty(
|
||||
span,
|
||||
TyKind::FnPtr(Box::new(ast::FnPtrTy {
|
||||
safety: p_sig.header.safety,
|
||||
ext: p_sig.header.ext,
|
||||
generic_params: ThinVec::new(),
|
||||
decl: Box::new(ast::FnDecl {
|
||||
inputs: fn_ptr_params,
|
||||
output: p_sig.decl.output.clone(),
|
||||
}),
|
||||
decl_span: span,
|
||||
})),
|
||||
);
|
||||
let primal_fn_ptr = ecx.expr(span, ast::ExprKind::Cast(primal_path_expr, fn_ptr_ty));
|
||||
|
||||
let diff_path_expr = gen_turbofish_expr(ecx, diff, generics, span, is_impl);
|
||||
|
||||
let tuple_expr = ecx.expr_tuple(
|
||||
@@ -529,7 +576,7 @@ fn call_autodiff(
|
||||
let call_expr = ecx.expr_call(
|
||||
span,
|
||||
ecx.expr_path(enzyme_path),
|
||||
vec![primal_path_expr, diff_path_expr, tuple_expr].into(),
|
||||
vec![primal_fn_ptr, diff_path_expr, tuple_expr].into(),
|
||||
);
|
||||
|
||||
ecx.stmt_expr(call_expr)
|
||||
|
||||
@@ -4,10 +4,9 @@
|
||||
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{AttrStyle, token};
|
||||
use rustc_attr_parsing as attr;
|
||||
use rustc_attr_parsing::parser::MetaItemOrLitParser;
|
||||
use rustc_attr_parsing::parser::{AllowExprMetavar, MetaItemOrLitParser};
|
||||
use rustc_attr_parsing::{
|
||||
AttributeParser, CFG_TEMPLATE, ParsedDescription, ShouldEmit, parse_cfg_entry,
|
||||
self as attr, AttributeParser, CFG_TEMPLATE, ParsedDescription, ShouldEmit, parse_cfg_entry,
|
||||
};
|
||||
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
|
||||
use rustc_hir::attrs::CfgEntry;
|
||||
@@ -44,6 +43,7 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result<CfgEntry,
|
||||
let meta = MetaItemOrLitParser::parse_single(
|
||||
&mut parser,
|
||||
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
|
||||
AllowExprMetavar::Yes,
|
||||
)
|
||||
.map_err(|diag| diag.emit())?;
|
||||
let cfg = AttributeParser::parse_single_args(
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
pub(crate) use Ty::*;
|
||||
use rustc_ast::{self as ast, Expr, GenericArg, GenericParamKind, Generics, SelfKind, TyKind};
|
||||
use rustc_expand::base::ExtCtxt;
|
||||
use rustc_span::source_map::respan;
|
||||
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw};
|
||||
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, respan};
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
/// A path, e.g., `::std::option::Option::<i32>` (global). Has support
|
||||
|
||||
@@ -51,7 +51,7 @@ pub(crate) fn expand_option_env<'cx>(
|
||||
|
||||
let sp = cx.with_def_site_ctxt(sp);
|
||||
let value = lookup_env(cx, var);
|
||||
cx.sess.psess.env_depinfo.borrow_mut().insert((var, value.as_ref().ok().copied()));
|
||||
cx.sess.env_depinfo.borrow_mut().insert((var, value.as_ref().ok().copied()));
|
||||
let e = match value {
|
||||
Err(VarError::NotPresent) => {
|
||||
let lt = cx.lifetime(sp, Ident::new(kw::StaticLifetime, sp));
|
||||
@@ -130,7 +130,7 @@ pub(crate) fn expand_env<'cx>(
|
||||
|
||||
let span = cx.with_def_site_ctxt(sp);
|
||||
let value = lookup_env(cx, var);
|
||||
cx.sess.psess.env_depinfo.borrow_mut().insert((var, value.as_ref().ok().copied()));
|
||||
cx.sess.env_depinfo.borrow_mut().insert((var, value.as_ref().ok().copied()));
|
||||
let e = match value {
|
||||
Err(err) => {
|
||||
let ExprKind::Lit(token::Lit {
|
||||
@@ -140,18 +140,21 @@ pub(crate) fn expand_env<'cx>(
|
||||
unreachable!("`expr_to_string` ensures this is a string lit")
|
||||
};
|
||||
|
||||
let var = var.as_str();
|
||||
let guar = match err {
|
||||
VarError::NotPresent => {
|
||||
if let Some(msg_from_user) = custom_msg {
|
||||
cx.dcx()
|
||||
.emit_err(errors::EnvNotDefinedWithUserMessage { span, msg_from_user })
|
||||
} else if let Some(suggested_var) = find_similar_cargo_var(var.as_str()) {
|
||||
} else if let Some(suggested_var) = find_similar_cargo_var(var)
|
||||
&& suggested_var != var
|
||||
{
|
||||
cx.dcx().emit_err(errors::EnvNotDefined::CargoEnvVarTypo {
|
||||
span,
|
||||
var: *symbol,
|
||||
suggested_var: Symbol::intern(suggested_var),
|
||||
})
|
||||
} else if is_cargo_env_var(var.as_str()) {
|
||||
} else if is_cargo_env_var(var) {
|
||||
cx.dcx().emit_err(errors::EnvNotDefined::CargoEnvVar {
|
||||
span,
|
||||
var: *symbol,
|
||||
@@ -177,7 +180,7 @@ pub(crate) fn expand_env<'cx>(
|
||||
ExpandResult::Ready(MacEager::expr(e))
|
||||
}
|
||||
|
||||
/// Returns `true` if an environment variable from `env!` is one used by Cargo.
|
||||
/// Returns `true` if an environment variable from `env!` could be one used by Cargo.
|
||||
fn is_cargo_env_var(var: &str) -> bool {
|
||||
var.starts_with("CARGO_")
|
||||
|| var.starts_with("DEP_")
|
||||
@@ -187,25 +190,28 @@ fn is_cargo_env_var(var: &str) -> bool {
|
||||
const KNOWN_CARGO_VARS: &[&str] = &[
|
||||
// List of known Cargo environment variables that are set for crates (not build scripts, OUT_DIR etc).
|
||||
// See: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates
|
||||
// tidy-alphabetical-start
|
||||
"CARGO_BIN_NAME",
|
||||
"CARGO_CRATE_NAME",
|
||||
"CARGO_MANIFEST_DIR",
|
||||
"CARGO_MANIFEST_PATH",
|
||||
"CARGO_PKG_AUTHORS",
|
||||
"CARGO_PKG_DESCRIPTION",
|
||||
"CARGO_PKG_HOMEPAGE",
|
||||
"CARGO_PKG_LICENSE",
|
||||
"CARGO_PKG_LICENSE_FILE",
|
||||
"CARGO_PKG_NAME",
|
||||
"CARGO_PKG_README",
|
||||
"CARGO_PKG_REPOSITORY",
|
||||
"CARGO_PKG_RUST_VERSION",
|
||||
"CARGO_PKG_VERSION",
|
||||
"CARGO_PKG_VERSION_MAJOR",
|
||||
"CARGO_PKG_VERSION_MINOR",
|
||||
"CARGO_PKG_VERSION_PATCH",
|
||||
"CARGO_PKG_VERSION_PRE",
|
||||
"CARGO_PKG_AUTHORS",
|
||||
"CARGO_PKG_NAME",
|
||||
"CARGO_PKG_DESCRIPTION",
|
||||
"CARGO_PKG_HOMEPAGE",
|
||||
"CARGO_PKG_REPOSITORY",
|
||||
"CARGO_PKG_LICENSE",
|
||||
"CARGO_PKG_LICENSE_FILE",
|
||||
"CARGO_PKG_RUST_VERSION",
|
||||
"CARGO_PKG_README",
|
||||
"CARGO_MANIFEST_DIR",
|
||||
"CARGO_MANIFEST_PATH",
|
||||
"CARGO_CRATE_NAME",
|
||||
"CARGO_BIN_NAME",
|
||||
"CARGO_PRIMARY_PACKAGE",
|
||||
"CARGO_TARGET_TMPDIR",
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
|
||||
fn find_similar_cargo_var(var: &str) -> Option<&'static str> {
|
||||
@@ -219,7 +225,13 @@ fn find_similar_cargo_var(var: &str) -> Option<&'static str> {
|
||||
let mut best_distance = usize::MAX;
|
||||
|
||||
for &known_var in KNOWN_CARGO_VARS {
|
||||
if let Some(distance) = edit_distance(var, known_var, max_dist) {
|
||||
if let Some(mut distance) = edit_distance(var, known_var, max_dist) {
|
||||
// assume `PACKAGE` to equals `PKG`
|
||||
// (otherwise, `d("CARGO_PACKAGE_NAME", "CARGO_PKG_NAME") == d("CARGO_PACKAGE_NAME", "CARGO_CRATE_NAME") == 4`)
|
||||
if var.contains("PACKAGE") && known_var.contains("PKG") {
|
||||
distance = distance.saturating_sub(const { "PACKAGE".len() - "PKG".len() }) // == d("PACKAGE", "PKG")
|
||||
}
|
||||
|
||||
if distance < best_distance {
|
||||
best_distance = distance;
|
||||
best_match = Some(known_var);
|
||||
|
||||
@@ -545,6 +545,7 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
|
||||
#[derive(Diagnostic)]
|
||||
pub(crate) enum EnvNotDefined<'a> {
|
||||
#[diag("environment variable `{$var}` not defined at compile time")]
|
||||
#[help("`{$var}` may not be available for the current Cargo target")]
|
||||
#[help(
|
||||
"Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead"
|
||||
)]
|
||||
|
||||
@@ -180,7 +180,7 @@ fn usize(&self) -> Box<Ty> {
|
||||
}
|
||||
|
||||
fn ptr_alignment(&self) -> Box<Ty> {
|
||||
let path = self.cx.std_path(&[sym::ptr, sym::Alignment]);
|
||||
let path = self.cx.std_path(&[sym::mem, sym::Alignment]);
|
||||
let path = self.cx.path(self.span, path);
|
||||
self.cx.ty_path(path)
|
||||
}
|
||||
|
||||
@@ -277,7 +277,6 @@ fn load_binary_file(
|
||||
match cx.source_map().load_binary_file(&resolved_path) {
|
||||
Ok(data) => {
|
||||
cx.sess
|
||||
.psess
|
||||
.file_depinfo
|
||||
.borrow_mut()
|
||||
.insert(Symbol::intern(&resolved_path.to_string_lossy()));
|
||||
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
# TARGET_TRIPLE: x86_64-pc-windows-gnu
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: CPU features
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
@@ -56,7 +56,7 @@ jobs:
|
||||
run: .github/scripts/free-disk-space.sh
|
||||
|
||||
- name: Cache cargo target dir
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: build/cg_clif
|
||||
key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
name: Security audit
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 10 * * 1' # every monday at 10:00 UTC
|
||||
permissions:
|
||||
issues: write
|
||||
checks: write
|
||||
jobs:
|
||||
audit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: |
|
||||
sed -i 's/components.*/components = []/' rust-toolchain.toml
|
||||
- uses: rustsec/audit-check@v2.0.0
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
+21
-11
@@ -19,12 +19,22 @@ env:
|
||||
RUSTFLAGS: "-Dwarnings"
|
||||
|
||||
jobs:
|
||||
todo_check:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Check todo
|
||||
run: ./y.sh check-todo
|
||||
|
||||
rustfmt:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Avoid installing rustc-dev
|
||||
run: |
|
||||
@@ -78,14 +88,14 @@ jobs:
|
||||
TARGET_TRIPLE: x86_64-pc-windows-gnu
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: CPU features
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: cat /proc/cpuinfo
|
||||
|
||||
- name: Cache cargo target dir
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: build/cg_clif
|
||||
key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain.toml', '**/Cargo.lock') }}
|
||||
@@ -127,7 +137,7 @@ jobs:
|
||||
timeout-minutes: 60
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: CPU features
|
||||
run: cat /proc/cpuinfo
|
||||
@@ -149,13 +159,13 @@ jobs:
|
||||
timeout-minutes: 60
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: CPU features
|
||||
run: cat /proc/cpuinfo
|
||||
|
||||
- name: Cache cargo target dir
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: build/cg_clif
|
||||
key: ${{ runner.os }}-x86_64-unknown-linux-gnu-cargo-build-target-${{ hashFiles('rust-toolchain.toml', '**/Cargo.lock') }}
|
||||
@@ -201,10 +211,10 @@ jobs:
|
||||
TARGET_TRIPLE: x86_64-pc-windows-gnu
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Cache cargo target dir
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: build/cg_clif
|
||||
key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-dist-cargo-build-target-${{ hashFiles('rust-toolchain.toml', '**/Cargo.lock') }}
|
||||
@@ -223,7 +233,7 @@ jobs:
|
||||
run: tar cvfJ cg_clif.tar.xz dist
|
||||
|
||||
- name: Upload prebuilt cg_clif
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: cg_clif-${{ matrix.env.TARGET_TRIPLE }}
|
||||
path: cg_clif.tar.xz
|
||||
@@ -232,7 +242,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
if: ${{ github.ref == 'refs/heads/main' }}
|
||||
needs: [rustfmt, test, bench, dist]
|
||||
needs: [todo_check, rustfmt, test, bench, dist]
|
||||
|
||||
permissions:
|
||||
contents: write # for creating the dev tag and release
|
||||
@@ -242,7 +252,7 @@ jobs:
|
||||
cancel-in-progress: true
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Download all built artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
@@ -11,13 +11,13 @@ jobs:
|
||||
timeout-minutes: 60
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: CPU features
|
||||
run: cat /proc/cpuinfo
|
||||
|
||||
- name: Cache cargo target dir
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: build/cg_clif
|
||||
key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain.toml', 'Cargo.lock') }}
|
||||
@@ -31,13 +31,13 @@ jobs:
|
||||
timeout-minutes: 60
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: CPU features
|
||||
run: cat /proc/cpuinfo
|
||||
|
||||
- name: Cache cargo target dir
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: build/cg_clif
|
||||
key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain.toml', 'Cargo.lock') }}
|
||||
|
||||
@@ -28,9 +28,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.19.1"
|
||||
version = "3.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
|
||||
checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
]
|
||||
@@ -43,42 +43,46 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-assembler-x64"
|
||||
version = "0.128.3"
|
||||
version = "0.130.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0377b13bf002a0774fcccac4f1102a10f04893d24060cf4b7350c87e4cbb647c"
|
||||
checksum = "4f248321c6a7d4de5dcf2939368e96a397ad3f53b6a076e38d0104d1da326d37"
|
||||
dependencies = [
|
||||
"cranelift-assembler-x64-meta",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-assembler-x64-meta"
|
||||
version = "0.128.3"
|
||||
version = "0.130.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfa027979140d023b25bf7509fb7ede3a54c3d3871fb5ead4673c4b633f671a2"
|
||||
checksum = "ab6d78ff1f7d9bf8b7e1afbedbf78ba49e38e9da479d4c8a2db094e22f64e2bc"
|
||||
dependencies = [
|
||||
"cranelift-srcgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-bforest"
|
||||
version = "0.128.3"
|
||||
version = "0.130.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "618e4da87d9179a70b3c2f664451ca8898987aa6eb9f487d16988588b5d8cc40"
|
||||
checksum = "6b6005ba640213a5b95382aeaf6b82bf028309581c8d7349778d66f27dc1180b"
|
||||
dependencies = [
|
||||
"cranelift-entity",
|
||||
"wasmtime-internal-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-bitset"
|
||||
version = "0.128.3"
|
||||
version = "0.130.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db53764b5dad233b37b8f5dc54d3caa9900c54579195e00f17ea21f03f71aaa7"
|
||||
checksum = "81fb5b134a12b559ff0c0f5af0fcd755ad380723b5016c4e0d36f74d39485340"
|
||||
dependencies = [
|
||||
"wasmtime-internal-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen"
|
||||
version = "0.128.3"
|
||||
version = "0.130.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ae927f1d8c0abddaa863acd201471d56e7fc6c3925104f4861ed4dc3e28b421"
|
||||
checksum = "85837de8be7f17a4034a6b08816f05a3144345d2091937b39d415990daca28f4"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"cranelift-assembler-x64",
|
||||
@@ -90,21 +94,22 @@ dependencies = [
|
||||
"cranelift-entity",
|
||||
"cranelift-isle",
|
||||
"gimli",
|
||||
"hashbrown",
|
||||
"hashbrown 0.16.1",
|
||||
"libm",
|
||||
"log",
|
||||
"regalloc2",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"smallvec",
|
||||
"target-lexicon",
|
||||
"wasmtime-internal-math",
|
||||
"wasmtime-internal-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-meta"
|
||||
version = "0.128.3"
|
||||
version = "0.130.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3fcf1e3e6757834bd2584f4cbff023fcc198e9279dcb5d684b4bb27a9b19f54"
|
||||
checksum = "e433faa87d38e5b8ff469e44a26fea4f93e58abd7a7c10bad9810056139700c9"
|
||||
dependencies = [
|
||||
"cranelift-assembler-x64-meta",
|
||||
"cranelift-codegen-shared",
|
||||
@@ -114,33 +119,34 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-shared"
|
||||
version = "0.128.3"
|
||||
version = "0.130.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "205dcb9e6ccf9d368b7466be675ff6ee54a63e36da6fe20e72d45169cf6fd254"
|
||||
checksum = "5397ba61976e13944ca71230775db13ee1cb62849701ed35b753f4761ed0a9b7"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-control"
|
||||
version = "0.128.3"
|
||||
version = "0.130.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "108eca9fcfe86026054f931eceaf57b722c1b97464bf8265323a9b5877238817"
|
||||
checksum = "cc81c88765580720eb30f4fc2c1bfdb75fcbf3094f87b3cd69cecca79d77a245"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-entity"
|
||||
version = "0.128.3"
|
||||
version = "0.130.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0d96496910065d3165f84ff8e1e393916f4c086f88ac8e1b407678bc78735aa"
|
||||
checksum = "463feed5d46cf8763f3ba3045284cf706dd161496e20ec9c14afbb4ba09b9e66"
|
||||
dependencies = [
|
||||
"cranelift-bitset",
|
||||
"wasmtime-internal-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-frontend"
|
||||
version = "0.128.3"
|
||||
version = "0.130.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e303983ad7e23c850f24d9c41fc3cb346e1b930f066d3966545e4c98dac5c9fb"
|
||||
checksum = "a4c5eca7696c1c04ab4c7ed8d18eadbb47d6cc9f14ec86fe0881bf1d7e97e261"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"log",
|
||||
@@ -150,15 +156,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-isle"
|
||||
version = "0.128.3"
|
||||
version = "0.130.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24b0cf8d867d891245836cac7abafb0a5b0ea040a019d720702b3b8bcba40bfa"
|
||||
checksum = "f1153844610cc9c6da8cf10ce205e45da1a585b7688ed558aa808bbe2e4e6d77"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-jit"
|
||||
version = "0.128.3"
|
||||
version = "0.130.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcf1e35da6eca2448395f483eb172ce71dd7842f7dc96f44bb8923beafe43c6d"
|
||||
checksum = "41836de8321b303d3d4188e58cc09c30c7645337342acfcfb363732695cae098"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-codegen",
|
||||
@@ -176,9 +182,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-module"
|
||||
version = "0.128.3"
|
||||
version = "0.130.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "792ba2a54100e34f8a36e3e329a5207cafd1f0918a031d34695db73c163fdcc7"
|
||||
checksum = "b731f66cb1b69b60a74216e632968ebdbb95c488d26aa1448ec226ae0ffec33e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-codegen",
|
||||
@@ -187,9 +193,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-native"
|
||||
version = "0.128.3"
|
||||
version = "0.130.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e24b641e315443e27807b69c440fe766737d7e718c68beb665a2d69259c77bf3"
|
||||
checksum = "a97b583fe9a60f06b0464cee6be5a17f623fd91b217aaac99b51b339d19911af"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"libc",
|
||||
@@ -198,9 +204,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-object"
|
||||
version = "0.128.3"
|
||||
version = "0.130.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecba1f219a201cf946150538e631defd620c5051b62c52ecb89a0004bab263d4"
|
||||
checksum = "9809d2d419cd18f17377f4ce64a7ad22eeda0d042c08833d3796657f1ddebc82"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-codegen",
|
||||
@@ -213,9 +219,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-srcgen"
|
||||
version = "0.128.3"
|
||||
version = "0.130.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4e378a54e7168a689486d67ee1f818b7e5356e54ae51a1d7a53f4f13f7f8b7a"
|
||||
checksum = "8594dc6bb4860fa8292f1814c76459dbfb933e1978d8222de6380efce45c7cee"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
@@ -233,24 +239,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "fallible-iterator"
|
||||
version = "0.3.0"
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.5"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.32.3"
|
||||
version = "0.33.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7"
|
||||
checksum = "0bf7f043f89559805f8c7cacc432749b2fa0d0a0a9ee46ce47164ed5ba7f126c"
|
||||
dependencies = [
|
||||
"fallible-iterator",
|
||||
"fnv",
|
||||
"hashbrown 0.16.1",
|
||||
"indexmap",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
@@ -260,6 +267,12 @@ name = "hashbrown"
|
||||
version = "0.15.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
||||
dependencies = [
|
||||
"foldhash",
|
||||
]
|
||||
@@ -272,12 +285,12 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.10.0"
|
||||
version = "2.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
|
||||
checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
"hashbrown 0.16.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -325,12 +338,12 @@ checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.37.3"
|
||||
version = "0.38.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe"
|
||||
checksum = "271638cd5fa9cca89c4c304675ca658efc4e64a66c716b7cfe1afb4b9611dbbc"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"hashbrown",
|
||||
"hashbrown 0.16.1",
|
||||
"indexmap",
|
||||
"memchr",
|
||||
]
|
||||
@@ -355,13 +368,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regalloc2"
|
||||
version = "0.13.5"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08effbc1fa53aaebff69521a5c05640523fab037b34a4a2c109506bc938246fa"
|
||||
checksum = "952ddbfc6f9f64d006c3efd8c9851a6ba2f2b944ba94730db255d55006e0ffda"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"bumpalo",
|
||||
"hashbrown",
|
||||
"hashbrown 0.15.5",
|
||||
"log",
|
||||
"rustc-hash",
|
||||
"smallvec",
|
||||
@@ -468,24 +481,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-internal-jit-icache-coherence"
|
||||
version = "41.0.3"
|
||||
name = "wasmtime-internal-core"
|
||||
version = "43.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bada5ca1cc47df7d14100e2254e187c2486b426df813cea2dd2553a7469f7674"
|
||||
checksum = "e671917bb6856ae360cb59d7aaf26f1cfd042c7b924319dd06fd380739fc0b2e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"windows-sys 0.61.2",
|
||||
"hashbrown 0.16.1",
|
||||
"libm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-internal-math"
|
||||
version = "41.0.3"
|
||||
name = "wasmtime-internal-jit-icache-coherence"
|
||||
version = "43.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf6f615d528eda9adc6eefb062135f831b5215c348f4c3ec3e143690c730605b"
|
||||
checksum = "9b3112806515fac8495883885eb8dbdde849988ae91fe6beb544c0d7c0f4c9aa"
|
||||
dependencies = [
|
||||
"libm",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasmtime-internal-core",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -8,15 +8,15 @@ crate-type = ["dylib"]
|
||||
|
||||
[dependencies]
|
||||
# These have to be in sync with each other
|
||||
cranelift-codegen = { version = "0.128.3", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] }
|
||||
cranelift-frontend = { version = "0.128.3" }
|
||||
cranelift-module = { version = "0.128.3" }
|
||||
cranelift-native = { version = "0.128.3" }
|
||||
cranelift-jit = { version = "0.128.3", optional = true }
|
||||
cranelift-object = { version = "0.128.3" }
|
||||
cranelift-codegen = { version = "0.130.0", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] }
|
||||
cranelift-frontend = { version = "0.130.0" }
|
||||
cranelift-module = { version = "0.130.0" }
|
||||
cranelift-native = { version = "0.130.0" }
|
||||
cranelift-jit = { version = "0.130.0", optional = true }
|
||||
cranelift-object = { version = "0.130.0" }
|
||||
target-lexicon = "0.13"
|
||||
gimli = { version = "0.32", default-features = false, features = ["write"] }
|
||||
object = { version = "0.37.3", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
|
||||
gimli = { version = "0.33", default-features = false, features = ["write"] }
|
||||
object = { version = "0.38.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
|
||||
|
||||
indexmap = "2.0.0"
|
||||
libloading = { version = "0.9.0", optional = true }
|
||||
@@ -24,12 +24,12 @@ smallvec = "1.8.1"
|
||||
|
||||
[patch.crates-io]
|
||||
# Uncomment to use an unreleased version of cranelift
|
||||
#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-41.0.0" }
|
||||
#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-41.0.0" }
|
||||
#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-41.0.0" }
|
||||
#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-41.0.0" }
|
||||
#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-41.0.0" }
|
||||
#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-41.0.0" }
|
||||
#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-43.0.0" }
|
||||
#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-43.0.0" }
|
||||
#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-43.0.0" }
|
||||
#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-43.0.0" }
|
||||
#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-43.0.0" }
|
||||
#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-43.0.0" }
|
||||
|
||||
# Uncomment to use local checkout of cranelift
|
||||
#cranelift-codegen = { path = "../wasmtime/cranelift/codegen" }
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
mod rustc_info;
|
||||
mod shared_utils;
|
||||
mod tests;
|
||||
mod todo;
|
||||
mod utils;
|
||||
|
||||
fn usage() {
|
||||
@@ -38,6 +39,7 @@ enum Command {
|
||||
Test,
|
||||
AbiCafe,
|
||||
Bench,
|
||||
CheckTodo,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
@@ -66,6 +68,7 @@ fn main() {
|
||||
Some("test") => Command::Test,
|
||||
Some("abi-cafe") => Command::AbiCafe,
|
||||
Some("bench") => Command::Bench,
|
||||
Some("check-todo") => Command::CheckTodo,
|
||||
Some(flag) if flag.starts_with('-') => arg_error!("Expected command found flag {}", flag),
|
||||
Some(command) => arg_error!("Unknown command {}", command),
|
||||
None => {
|
||||
@@ -139,6 +142,10 @@ fn main() {
|
||||
process::exit(0);
|
||||
}
|
||||
|
||||
if command == Command::CheckTodo {
|
||||
todo::run();
|
||||
}
|
||||
|
||||
let rustup_toolchain_name = match (env::var("CARGO"), env::var("RUSTC"), env::var("RUSTDOC")) {
|
||||
(Ok(_), Ok(_), Ok(_)) => None,
|
||||
(_, Err(_), Err(_)) => Some(rustc_info::get_toolchain_name()),
|
||||
@@ -202,7 +209,7 @@ fn main() {
|
||||
))
|
||||
};
|
||||
match command {
|
||||
Command::Prepare => {
|
||||
Command::Prepare | Command::CheckTodo => {
|
||||
// Handled above
|
||||
}
|
||||
Command::Test => {
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
use std::ffi::OsStr;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
use std::{fs, process};
|
||||
|
||||
const EXTENSIONS: &[&str] =
|
||||
&["rs", "py", "js", "sh", "c", "cpp", "h", "md", "css", "ftl", "toml", "yml", "yaml"];
|
||||
|
||||
fn has_supported_extension(path: &Path) -> bool {
|
||||
path.extension().is_some_and(|ext| EXTENSIONS.iter().any(|e| ext == OsStr::new(e)))
|
||||
}
|
||||
|
||||
fn list_tracked_files() -> Result<Vec<PathBuf>, String> {
|
||||
let output = Command::new("git")
|
||||
.args(["ls-files", "-z"])
|
||||
.output()
|
||||
.map_err(|e| format!("Failed to run `git ls-files`: {e}"))?;
|
||||
|
||||
if !output.status.success() {
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
return Err(format!("`git ls-files` failed: {stderr}"));
|
||||
}
|
||||
|
||||
let mut files = Vec::new();
|
||||
for entry in output.stdout.split(|b| *b == 0) {
|
||||
if entry.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let path = std::str::from_utf8(entry).unwrap();
|
||||
files.push(PathBuf::from(path));
|
||||
}
|
||||
|
||||
Ok(files)
|
||||
}
|
||||
|
||||
pub(crate) fn run() -> ! {
|
||||
let files = list_tracked_files().unwrap();
|
||||
let mut error_count = 0;
|
||||
// Avoid embedding the task marker in source so greps only find real occurrences.
|
||||
let todo_marker = "todo".to_ascii_uppercase();
|
||||
|
||||
for file in files {
|
||||
if !has_supported_extension(&file) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let bytes = fs::read(&file).unwrap();
|
||||
let contents = std::str::from_utf8(&bytes).unwrap();
|
||||
|
||||
for (i, line) in contents.split('\n').enumerate() {
|
||||
let trimmed = line.trim();
|
||||
if trimmed.contains(&todo_marker) {
|
||||
eprintln!(
|
||||
"{}:{}: {} is used for tasks that should be done before merging a PR; if you want to leave a message in the codebase use FIXME",
|
||||
file.display(),
|
||||
i + 1,
|
||||
todo_marker
|
||||
);
|
||||
error_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if error_count == 0 {
|
||||
process::exit(0);
|
||||
}
|
||||
|
||||
eprintln!("found {} {}(s)", error_count, todo_marker);
|
||||
process::exit(1);
|
||||
}
|
||||
@@ -6,6 +6,7 @@ USAGE:
|
||||
./y.sh test [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen] [--skip-test TESTNAME]
|
||||
./y.sh abi-cafe [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen]
|
||||
./y.sh bench [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen]
|
||||
./y.sh check-todo
|
||||
|
||||
OPTIONS:
|
||||
--sysroot none|clif|llvm
|
||||
|
||||
@@ -2,9 +2,3 @@
|
||||
set -e
|
||||
|
||||
rm -rf target/ build_system/target download/ build/ dist/
|
||||
|
||||
# Kept for now in case someone updates their checkout of cg_clif before running clean_all.sh
|
||||
# FIXME remove at some point in the future
|
||||
rm y.bin y.bin.dSYM y.exe y.pdb 2>/dev/null || true
|
||||
rm -rf rand/ regex/ simple-raytracer/ portable-simd/ abi-checker/ abi-cafe/
|
||||
rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version}
|
||||
|
||||
@@ -33,24 +33,24 @@ fn main() {
|
||||
let n = f32x4([nan, nan, nan, nan]);
|
||||
|
||||
unsafe {
|
||||
let min0 = simd_fmin(x, y);
|
||||
let min1 = simd_fmin(y, x);
|
||||
let min0 = simd_minimum_number_nsz(x, y);
|
||||
let min1 = simd_minimum_number_nsz(y, x);
|
||||
assert_eq!(min0.into_array(), min1.into_array());
|
||||
let e = f32x4([1.0, 1.0, 3.0, 3.0]);
|
||||
assert_eq!(min0.into_array(), e.into_array());
|
||||
let minn = simd_fmin(x, n);
|
||||
let minn = simd_minimum_number_nsz(x, n);
|
||||
assert_eq!(minn.into_array(), x.into_array());
|
||||
let minn = simd_fmin(y, n);
|
||||
let minn = simd_minimum_number_nsz(y, n);
|
||||
assert_eq!(minn.into_array(), y.into_array());
|
||||
|
||||
let max0 = simd_fmax(x, y);
|
||||
let max1 = simd_fmax(y, x);
|
||||
let max0 = simd_maximum_number_nsz(x, y);
|
||||
let max1 = simd_maximum_number_nsz(y, x);
|
||||
assert_eq!(max0.into_array(), max1.into_array());
|
||||
let e = f32x4([2.0, 2.0, 4.0, 4.0]);
|
||||
assert_eq!(max0.into_array(), e.into_array());
|
||||
let maxn = simd_fmax(x, n);
|
||||
let maxn = simd_maximum_number_nsz(x, n);
|
||||
assert_eq!(maxn.into_array(), x.into_array());
|
||||
let maxn = simd_fmax(y, n);
|
||||
let maxn = simd_maximum_number_nsz(y, n);
|
||||
assert_eq!(maxn.into_array(), y.into_array());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
rustc_private,
|
||||
transparent_unions,
|
||||
auto_traits,
|
||||
freeze_impls,
|
||||
thread_local
|
||||
freeze_impls
|
||||
)]
|
||||
#![cfg_attr(not(all(windows, target_env = "gnu")), feature(thread_local))]
|
||||
#![no_core]
|
||||
#![allow(dead_code, internal_features, ambiguous_wide_pointer_comparisons)]
|
||||
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
#![feature(
|
||||
no_core,
|
||||
lang_items,
|
||||
never_type,
|
||||
linkage,
|
||||
extern_types,
|
||||
thread_local,
|
||||
repr_simd,
|
||||
rustc_private
|
||||
)]
|
||||
#![feature(no_core, lang_items, never_type, extern_types, thread_local, repr_simd, rustc_private)]
|
||||
#![cfg_attr(not(any(jit, target_vendor = "apple", windows)), feature(linkage))]
|
||||
#![no_core]
|
||||
#![allow(dead_code, non_camel_case_types, internal_features)]
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Most of these tests are copied from https://github.com/japaric/stdsimd/blob/0f4413d01c4f0c3ffbc5a69e9a37fbc7235b31a9/coresimd/arm/neon.rs
|
||||
|
||||
#![feature(portable_simd)]
|
||||
#![cfg_attr(target_arch = "aarch64", feature(portable_simd))]
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use std::arch::aarch64::*;
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
#![feature(
|
||||
core_intrinsics,
|
||||
coroutines,
|
||||
stmt_expr_attributes,
|
||||
coroutine_trait,
|
||||
repr_simd,
|
||||
tuple_trait,
|
||||
unboxed_closures
|
||||
)]
|
||||
#![feature(core_intrinsics, coroutines, coroutine_trait, repr_simd, tuple_trait, unboxed_closures)]
|
||||
#![allow(internal_features)]
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use std::arch::asm;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use std::arch::x86_64::*;
|
||||
use std::hint::black_box;
|
||||
@@ -173,6 +167,9 @@ enum Never {}
|
||||
|
||||
rust_call_abi();
|
||||
|
||||
// #[cfg(target_arch = "x86_64")]
|
||||
// inline_asm_call_custom_abi();
|
||||
|
||||
const fn no_str() -> Option<Box<str>> {
|
||||
None
|
||||
}
|
||||
@@ -279,6 +276,17 @@ unsafe fn test_simd() {
|
||||
|
||||
#[cfg(not(jit))]
|
||||
test_crc32();
|
||||
|
||||
#[cfg(not(jit))]
|
||||
test_xmm_roundtrip();
|
||||
#[cfg(not(jit))]
|
||||
if is_x86_feature_detected!("avx") {
|
||||
test_ymm_roundtrip();
|
||||
}
|
||||
#[cfg(not(jit))]
|
||||
if is_x86_feature_detected!("avx512f") {
|
||||
test_zmm_roundtrip();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -576,6 +584,65 @@ unsafe fn test_mm_cvtps_ph() {
|
||||
assert_eq_m128i(r, e);
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[cfg(not(jit))]
|
||||
unsafe fn test_xmm_roundtrip() {
|
||||
unsafe {
|
||||
let input = [1u8; 16];
|
||||
let mut output = [0u8; 16];
|
||||
|
||||
asm!(
|
||||
"movups {xmm}, [{input}]",
|
||||
"movups [{output}], {xmm}",
|
||||
input = in(reg) input.as_ptr(),
|
||||
output = in(reg) output.as_mut_ptr(),
|
||||
xmm = out(xmm_reg) _,
|
||||
);
|
||||
|
||||
assert_eq!(input, output);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[target_feature(enable = "avx")]
|
||||
#[cfg(not(jit))]
|
||||
unsafe fn test_ymm_roundtrip() {
|
||||
unsafe {
|
||||
let input = [1u8; 32];
|
||||
let mut output = [0u8; 32];
|
||||
|
||||
asm!(
|
||||
"vmovups {ymm}, [{input}]",
|
||||
"vmovups [{output}], {ymm}",
|
||||
input = in(reg) input.as_ptr(),
|
||||
output = in(reg) output.as_mut_ptr(),
|
||||
ymm = out(ymm_reg) _,
|
||||
);
|
||||
|
||||
assert_eq!(input, output);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[target_feature(enable = "avx512f")]
|
||||
#[cfg(not(jit))]
|
||||
unsafe fn test_zmm_roundtrip() {
|
||||
unsafe {
|
||||
let input = [1u8; 64];
|
||||
let mut output = [0u8; 64];
|
||||
|
||||
asm!(
|
||||
"vmovups {zmm}, [{input}]",
|
||||
"vmovups [{output}], {zmm}",
|
||||
input = in(reg) input.as_ptr(),
|
||||
output = in(reg) output.as_mut_ptr(),
|
||||
zmm = out(zmm_reg) _,
|
||||
);
|
||||
|
||||
assert_eq!(input, output);
|
||||
}
|
||||
}
|
||||
|
||||
fn test_checked_mul() {
|
||||
let u: Option<u8> = u8::from_str_radix("1000", 10).ok();
|
||||
assert_eq!(u, None);
|
||||
@@ -614,3 +681,18 @@ fn map(a: Option<(u8, Box<Instruction>)>) -> Option<Box<Instruction>> {
|
||||
Some((_, instr)) => Some(instr),
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME enable once inline asm sym references are stabilized in cg_clif
|
||||
// #[cfg(target_arch = "x86_64")]
|
||||
// fn inline_asm_call_custom_abi() {
|
||||
// use std::arch::{asm, naked_asm};
|
||||
//
|
||||
// #[unsafe(naked)]
|
||||
// unsafe extern "custom" fn double() {
|
||||
// naked_asm!("add rax, rax", "ret");
|
||||
// }
|
||||
//
|
||||
// let mut x: u64 = 21;
|
||||
// unsafe { asm!("call {}", sym double, inout("rax") x) };
|
||||
// assert_eq!(x, 42);
|
||||
// }
|
||||
|
||||
+1
-12
@@ -37,16 +37,7 @@ diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
|
||||
index bf2b6d59f88..d5ccce03bbf 100644
|
||||
--- a/library/core/src/sync/atomic.rs
|
||||
+++ b/library/core/src/sync/atomic.rs
|
||||
@@ -300,8 +300,6 @@ impl_atomic_primitive!(AtomicI32(i32), size("32"), align(4));
|
||||
impl_atomic_primitive!(AtomicU32(u32), size("32"), align(4));
|
||||
impl_atomic_primitive!(AtomicI64(i64), size("64"), align(8));
|
||||
impl_atomic_primitive!(AtomicU64(u64), size("64"), align(8));
|
||||
-impl_atomic_primitive!(AtomicI128(i128), size("128"), align(16));
|
||||
-impl_atomic_primitive!(AtomicU128(u128), size("128"), align(16));
|
||||
|
||||
#[cfg(target_pointer_width = "16")]
|
||||
impl_atomic_primitive!(AtomicIsize(isize), size("ptr"), align(2));
|
||||
@@ -3585,44 +3585,6 @@ pub const fn as_ptr(&self) -> *mut $int_type {
|
||||
@@ -3585,42 +3585,6 @@ pub const fn as_ptr(&self) -> *mut $int_type {
|
||||
8,
|
||||
u64 AtomicU64
|
||||
}
|
||||
@@ -62,7 +53,6 @@ index bf2b6d59f88..d5ccce03bbf 100644
|
||||
- unstable(feature = "integer_atomics", issue = "99069"),
|
||||
- rustc_const_unstable(feature = "integer_atomics", issue = "99069"),
|
||||
- rustc_const_unstable(feature = "integer_atomics", issue = "99069"),
|
||||
- rustc_diagnostic_item = "AtomicI128",
|
||||
- "i128",
|
||||
- "#![feature(integer_atomics)]\n\n",
|
||||
- atomic_min, atomic_max,
|
||||
@@ -81,7 +71,6 @@ index bf2b6d59f88..d5ccce03bbf 100644
|
||||
- unstable(feature = "integer_atomics", issue = "99069"),
|
||||
- rustc_const_unstable(feature = "integer_atomics", issue = "99069"),
|
||||
- rustc_const_unstable(feature = "integer_atomics", issue = "99069"),
|
||||
- rustc_diagnostic_item = "AtomicU128",
|
||||
- "u128",
|
||||
- "#![feature(integer_atomics)]\n\n",
|
||||
- atomic_umin, atomic_umax,
|
||||
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
From 116abc64add4d617104993a7a3011f20bcf31ef2 Mon Sep 17 00:00:00 2001
|
||||
From: bjorn3 <17426603+bjorn3@users.noreply.github.com>
|
||||
Date: Mon, 26 Jan 2026 16:20:58 +0000
|
||||
Subject: [PATCH] Ensure va_end doesn't get emitted unless VaList is actually
|
||||
used
|
||||
|
||||
---
|
||||
library/core/src/ffi/va_list.rs | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs
|
||||
index d0f1553..75129af 100644
|
||||
--- a/library/core/src/ffi/va_list.rs
|
||||
+++ b/library/core/src/ffi/va_list.rs
|
||||
@@ -217,6 +217,7 @@ impl Clone for VaList<'_> {
|
||||
|
||||
#[rustc_const_unstable(feature = "const_c_variadic", issue = "151787")]
|
||||
impl<'f> const Drop for VaList<'f> {
|
||||
+ #[inline]
|
||||
fn drop(&mut self) {
|
||||
// SAFETY: this variable argument list is being dropped, so won't be read from again.
|
||||
unsafe { va_end(self) }
|
||||
--
|
||||
2.43.0
|
||||
|
||||
@@ -4,13 +4,13 @@ Date: Sun, 15 Feb 2026 14:06:49 +0000
|
||||
Subject: [PATCH] Disable f16 math tests for cranelift
|
||||
|
||||
---
|
||||
coretests/tests/floats/mod.rs | 26 +++++++++++++-------------
|
||||
coretests/tests/num/floats.rs | 26 +++++++++++++-------------
|
||||
1 file changed, 13 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/coretests/tests/floats/mod.rs b/coretests/tests/floats/mod.rs
|
||||
index c61961f8584..d7b4fa20322 100644
|
||||
--- a/coretests/tests/floats/mod.rs
|
||||
+++ b/coretests/tests/floats/mod.rs
|
||||
--- a/coretests/tests/num/floats.rs
|
||||
+++ b/coretests/tests/num/floats.rs
|
||||
@@ -1534,7 +1534,7 @@ fn s_nan() -> Float {
|
||||
name: powf,
|
||||
attrs: {
|
||||
@@ -128,6 +128,5 @@ index c61961f8584..d7b4fa20322 100644
|
||||
f128: #[cfg(all(not(miri), target_has_reliable_f128_math))],
|
||||
},
|
||||
test {
|
||||
--
|
||||
--
|
||||
2.50.1
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[toolchain]
|
||||
channel = "nightly-2026-02-18"
|
||||
channel = "nightly-2026-03-25"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools", "rustfmt"]
|
||||
profile = "minimal"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user