commit
49261152b5
1172 changed files with 22473 additions and 16500 deletions
|
|
@ -15,7 +15,7 @@ standard library in the [Standard library developers Guide][std-dev-guide], comm
|
|||
## About the [rustc-dev-guide]
|
||||
|
||||
The [rustc-dev-guide] is meant to help document how rustc –the Rust compiler– works,
|
||||
as well as to help new contributors get involved in rustc development. It is recommend
|
||||
as well as to help new contributors get involved in rustc development. It is recommended
|
||||
to read and understand the [rustc-dev-guide] before making a contribution. This guide
|
||||
talks about the different bots in the Rust ecosystem, the Rust development tools,
|
||||
bootstrapping, the compiler architecture, source code representation, and more.
|
||||
|
|
|
|||
171
Cargo.lock
171
Cargo.lock
|
|
@ -193,12 +193,6 @@ dependencies = [
|
|||
"object",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "array_tool"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f8cb5d814eb646a863c4f24978cff2880c4be96ad8cde2c0f0678732902e271"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.4"
|
||||
|
|
@ -237,17 +231,6 @@ version = "0.10.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi 0.1.19",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
|
|
@ -356,7 +339,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"curl",
|
||||
"indexmap 2.0.0",
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"toml 0.5.11",
|
||||
|
|
@ -553,7 +536,7 @@ checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
|
|||
|
||||
[[package]]
|
||||
name = "clippy"
|
||||
version = "0.1.75"
|
||||
version = "0.1.76"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"clippy_config",
|
||||
|
|
@ -581,7 +564,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy_config"
|
||||
version = "0.1.75"
|
||||
version = "0.1.76"
|
||||
dependencies = [
|
||||
"rustc-semver",
|
||||
"serde",
|
||||
|
|
@ -604,14 +587,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy_lints"
|
||||
version = "0.1.75"
|
||||
version = "0.1.76"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"cargo_metadata 0.15.4",
|
||||
"clippy_config",
|
||||
"clippy_utils",
|
||||
"declare_clippy_lint",
|
||||
"if_chain",
|
||||
"itertools",
|
||||
"quine-mc_cluskey",
|
||||
"regex",
|
||||
|
|
@ -630,11 +612,10 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy_utils"
|
||||
version = "0.1.75"
|
||||
version = "0.1.76"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"clippy_config",
|
||||
"if_chain",
|
||||
"itertools",
|
||||
"rustc-semver",
|
||||
]
|
||||
|
|
@ -741,7 +722,7 @@ dependencies = [
|
|||
"getopts",
|
||||
"glob",
|
||||
"home",
|
||||
"indexmap 2.0.0",
|
||||
"indexmap",
|
||||
"lazycell",
|
||||
"libc",
|
||||
"miow",
|
||||
|
|
@ -1016,7 +997,7 @@ checksum = "a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69"
|
|||
|
||||
[[package]]
|
||||
name = "declare_clippy_lint"
|
||||
version = "0.1.75"
|
||||
version = "0.1.76"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"quote",
|
||||
|
|
@ -1247,26 +1228,13 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"humantime 1.3.0",
|
||||
"log",
|
||||
"regex",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
|
||||
dependencies = [
|
||||
"humantime 2.1.0",
|
||||
"humantime",
|
||||
"is-terminal",
|
||||
"log",
|
||||
"regex",
|
||||
|
|
@ -1380,7 +1348,7 @@ dependencies = [
|
|||
"intl-memoizer",
|
||||
"intl_pluralrules",
|
||||
"rustc-hash",
|
||||
"self_cell",
|
||||
"self_cell 0.10.3",
|
||||
"smallvec",
|
||||
"unic-langid",
|
||||
]
|
||||
|
|
@ -1610,7 +1578,7 @@ checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
|
|||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"fallible-iterator",
|
||||
"indexmap 2.0.0",
|
||||
"indexmap",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
"stable_deref_trait",
|
||||
|
|
@ -1646,9 +1614,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.19"
|
||||
version = "0.3.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782"
|
||||
checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
|
|
@ -1656,7 +1624,7 @@ dependencies = [
|
|||
"futures-sink",
|
||||
"futures-util",
|
||||
"http",
|
||||
"indexmap 1.9.3",
|
||||
"indexmap",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
|
|
@ -1677,12 +1645,6 @@ dependencies = [
|
|||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.2"
|
||||
|
|
@ -1702,15 +1664,6 @@ version = "0.4.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.2"
|
||||
|
|
@ -1802,15 +1755,6 @@ dependencies = [
|
|||
"libm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
|
||||
dependencies = [
|
||||
"quick-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.1.0"
|
||||
|
|
@ -2016,16 +1960,6 @@ version = "0.3.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.0.0"
|
||||
|
|
@ -2033,7 +1967,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.14.2",
|
||||
"hashbrown",
|
||||
"rustc-rayon",
|
||||
"serde",
|
||||
]
|
||||
|
|
@ -2119,7 +2053,7 @@ version = "0.4.8"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24fddda5af7e54bf7da53067d6e802dbcc381d0a8eef629df528e3ebf68755cb"
|
||||
dependencies = [
|
||||
"hermit-abi 0.3.2",
|
||||
"hermit-abi",
|
||||
"rustix",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
|
@ -2195,12 +2129,10 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "jsonpath_lib"
|
||||
version = "0.2.6"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61352ec23883402b7d30b3313c16cbabefb8907361c4eb669d990cbb87ceee5a"
|
||||
checksum = "eaa63191d68230cccb81c5aa23abd53ed64d83337cacbb25a7b8c7979523774f"
|
||||
dependencies = [
|
||||
"array_tool",
|
||||
"env_logger 0.7.1",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
@ -2418,7 +2350,7 @@ dependencies = [
|
|||
"clap",
|
||||
"clap_complete",
|
||||
"elasticlunr-rs",
|
||||
"env_logger 0.10.0",
|
||||
"env_logger",
|
||||
"handlebars",
|
||||
"log",
|
||||
"memchr",
|
||||
|
|
@ -2543,7 +2475,7 @@ dependencies = [
|
|||
"aes",
|
||||
"colored",
|
||||
"ctrlc",
|
||||
"env_logger 0.10.0",
|
||||
"env_logger",
|
||||
"getrandom",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
|
|
@ -2647,7 +2579,7 @@ version = "1.16.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||
dependencies = [
|
||||
"hermit-abi 0.3.2",
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
|
|
@ -2659,15 +2591,15 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
|||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.32.0"
|
||||
version = "0.32.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe"
|
||||
checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"crc32fast",
|
||||
"flate2",
|
||||
"hashbrown 0.14.2",
|
||||
"indexmap 2.0.0",
|
||||
"hashbrown",
|
||||
"indexmap",
|
||||
"memchr",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
|
|
@ -2752,11 +2684,11 @@ dependencies = [
|
|||
"camino",
|
||||
"clap",
|
||||
"derive_builder",
|
||||
"env_logger 0.10.0",
|
||||
"env_logger",
|
||||
"fs_extra",
|
||||
"glob",
|
||||
"humansize",
|
||||
"humantime 2.1.0",
|
||||
"humantime",
|
||||
"log",
|
||||
"reqwest",
|
||||
"serde",
|
||||
|
|
@ -3106,12 +3038,6 @@ version = "0.4.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e9e1dcb320d6839f6edb64f7a4a59d39b30480d4d1765b56873f7c858538a5fe"
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "1.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||
|
||||
[[package]]
|
||||
name = "quine-mc_cluskey"
|
||||
version = "0.2.4"
|
||||
|
|
@ -3359,7 +3285,7 @@ name = "rustbook"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"env_logger 0.10.0",
|
||||
"env_logger",
|
||||
"mdbook",
|
||||
]
|
||||
|
||||
|
|
@ -3743,7 +3669,7 @@ dependencies = [
|
|||
"bitflags 1.3.2",
|
||||
"elsa",
|
||||
"ena",
|
||||
"indexmap 2.0.0",
|
||||
"indexmap",
|
||||
"itertools",
|
||||
"jobserver",
|
||||
"libc",
|
||||
|
|
@ -3817,6 +3743,7 @@ dependencies = [
|
|||
"rustc_query_system",
|
||||
"rustc_resolve",
|
||||
"rustc_session",
|
||||
"rustc_smir",
|
||||
"rustc_span",
|
||||
"rustc_symbol_mangling",
|
||||
"rustc_target",
|
||||
|
|
@ -4043,11 +3970,22 @@ name = "rustc_index"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"rustc_index_macros",
|
||||
"rustc_macros",
|
||||
"rustc_serialize",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_index_macros"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.29",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_infer"
|
||||
version = "0.0.0"
|
||||
|
|
@ -4504,7 +4442,7 @@ dependencies = [
|
|||
name = "rustc_serialize"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"indexmap 2.0.0",
|
||||
"indexmap",
|
||||
"rustc_macros",
|
||||
"smallvec",
|
||||
"tempfile",
|
||||
|
|
@ -4554,7 +4492,7 @@ dependencies = [
|
|||
name = "rustc_span"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"indexmap 2.0.0",
|
||||
"indexmap",
|
||||
"md-5",
|
||||
"rustc_arena",
|
||||
"rustc_data_structures",
|
||||
|
|
@ -4713,7 +4651,7 @@ dependencies = [
|
|||
"arrayvec",
|
||||
"askama",
|
||||
"expect-test",
|
||||
"indexmap 2.0.0",
|
||||
"indexmap",
|
||||
"itertools",
|
||||
"minifier",
|
||||
"once_cell",
|
||||
|
|
@ -4903,9 +4841,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "self_cell"
|
||||
version = "0.10.2"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ef965a420fe14fdac7dd018862966a4c14094f900e1650bbc71ddd7d580c8af"
|
||||
checksum = "e14e4d63b804dc0c7ec4a1e52bcb63f02c7ac94476755aa579edac21e01f915d"
|
||||
dependencies = [
|
||||
"self_cell 1.0.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "self_cell"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e388332cd64eb80cd595a00941baf513caffae8dce9cfd0467fc9c66397dade6"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
|
|
@ -4942,7 +4889,7 @@ version = "1.0.99"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3"
|
||||
dependencies = [
|
||||
"indexmap 2.0.0",
|
||||
"indexmap",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
|
|
@ -5122,8 +5069,8 @@ dependencies = [
|
|||
"core",
|
||||
"dlmalloc",
|
||||
"fortanix-sgx-abi",
|
||||
"hashbrown 0.14.2",
|
||||
"hermit-abi 0.3.2",
|
||||
"hashbrown",
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
|
|
@ -5430,7 +5377,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "4db52ee8fec06e119b692ef3dd2c4cf621a99204c1b8c47407870ed050305b9b"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
"hashbrown 0.14.2",
|
||||
"hashbrown",
|
||||
"object",
|
||||
"tracing",
|
||||
]
|
||||
|
|
@ -5602,7 +5549,7 @@ version = "0.19.11"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "266f016b7f039eec8a1a80dfe6156b633d208b9fccca5e4db1d6775b0c4e34a7"
|
||||
dependencies = [
|
||||
"indexmap 2.0.0",
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
|
|
|
|||
25
RELEASES.md
25
RELEASES.md
|
|
@ -47,8 +47,8 @@ Stabilized APIs
|
|||
- [`core::num::Saturating`](https://doc.rust-lang.org/stable/std/num/struct.Saturating.html)
|
||||
- [`impl From<io::Stdout> for std::process::Stdio`](https://doc.rust-lang.org/stable/std/process/struct.Stdio.html#impl-From%3CStdout%3E-for-Stdio)
|
||||
- [`impl From<io::Stderr> for std::process::Stdio`](https://doc.rust-lang.org/stable/std/process/struct.Stdio.html#impl-From%3CStderr%3E-for-Stdio)
|
||||
- [`impl From<OwnedHandle> for std::process::Child{Stdin, Stdout, Stderr}`](https://doc.rust-lang.org/stable/std/process/struct.Stdio.html#impl-From%3CStderr%3E-for-Stdio)
|
||||
- [`impl From<OwnedFd> for std::process::Child{Stdin, Stdout, Stderr}`](https://doc.rust-lang.org/stable/std/process/struct.Stdio.html#impl-From%3CStderr%3E-for-Stdio)
|
||||
- [`impl From<OwnedHandle> for std::process::Child{Stdin, Stdout, Stderr}`](https://doc.rust-lang.org/stable/std/process/struct.ChildStderr.html#impl-From%3COwnedHandle%3E-for-ChildStderr)
|
||||
- [`impl From<OwnedFd> for std::process::Child{Stdin, Stdout, Stderr}`](https://doc.rust-lang.org/stable/std/process/struct.ChildStderr.html#impl-From%3COwnedFd%3E-for-ChildStderr)
|
||||
- [`std::ffi::OsString::from_encoded_bytes_unchecked`](https://doc.rust-lang.org/stable/std/ffi/struct.OsString.html#method.from_encoded_bytes_unchecked)
|
||||
- [`std::ffi::OsString::into_encoded_bytes`](https://doc.rust-lang.org/stable/std/ffi/struct.OsString.html#method.into_encoded_bytes)
|
||||
- [`std::ffi::OsStr::from_encoded_bytes_unchecked`](https://doc.rust-lang.org/stable/std/ffi/struct.OsStr.html#method.from_encoded_bytes_unchecked)
|
||||
|
|
@ -71,17 +71,17 @@ These APIs are now stable in const contexts:
|
|||
Cargo
|
||||
-----
|
||||
|
||||
- [fix: Set MSRV for internal packages](https://github.com/rust-lang/cargo/pull/12381/)
|
||||
- [config: merge lists in precedence order](https://github.com/rust-lang/cargo/pull/12515/)
|
||||
- [fix(update): Clarify meaning of --aggressive as --recursive](https://github.com/rust-lang/cargo/pull/12544/)
|
||||
- [fix(update): Make `-p` more convenient by being positional](https://github.com/rust-lang/cargo/pull/12545/)
|
||||
- [feat(help): Add styling to help output ](https://github.com/rust-lang/cargo/pull/12578/)
|
||||
- [feat(pkgid): Allow incomplete versions when unambigious](https://github.com/rust-lang/cargo/pull/12614/)
|
||||
- [feat: stabilize credential-process and registry-auth](https://github.com/rust-lang/cargo/pull/12649/)
|
||||
- [feat(cli): Add '-n' to dry-run](https://github.com/rust-lang/cargo/pull/12660/)
|
||||
- [In `Cargo.toml`, stabilize `[lints]`](https://github.com/rust-lang/cargo/pull/12648/)
|
||||
- [Stabilize credential-process and registry-auth](https://github.com/rust-lang/cargo/pull/12649/)
|
||||
- [Stabilize `--keep-going` build flag](https://github.com/rust-lang/cargo/pull/12568/)
|
||||
- [Add styling to `--help` output](https://github.com/rust-lang/cargo/pull/12578/)
|
||||
- [For `cargo clean`, add `--dry-run` flag and summary line at the end](https://github.com/rust-lang/cargo/pull/12638)
|
||||
- [For `cargo update`, make `--package` more convenient by being positional](https://github.com/rust-lang/cargo/pull/12545/)
|
||||
- [For `cargo update`, clarify meaning of --aggressive as --recursive](https://github.com/rust-lang/cargo/pull/12544/)
|
||||
- [Add '-n' as an alias for `--dry-run`](https://github.com/rust-lang/cargo/pull/12660/)
|
||||
- [Allow version-prefixes in pkgid's (e.g. `--package` flags) to resolve ambiguities](https://github.com/rust-lang/cargo/pull/12614/)
|
||||
- [In `.cargo/config.toml`, merge lists in precedence order](https://github.com/rust-lang/cargo/pull/12515/)
|
||||
- [Add support for `target.'cfg(..)'.linker`](https://github.com/rust-lang/cargo/pull/12535/)
|
||||
- [Stabilize `--keep-going`](https://github.com/rust-lang/cargo/pull/12568/)
|
||||
- [feat: Stabilize lints](https://github.com/rust-lang/cargo/pull/12648/)
|
||||
|
||||
<a id="1.74.0-Rustdoc"></a>
|
||||
|
||||
|
|
@ -200,7 +200,6 @@ These APIs are now stable in const contexts:
|
|||
Cargo
|
||||
-----
|
||||
|
||||
- [Encode URL params correctly for `SourceId` in `Cargo.lock`.](https://github.com/rust-lang/cargo/pull/12280/)
|
||||
- [Bail out an error when using `cargo::` in custom build script.](https://github.com/rust-lang/cargo/pull/12332/)
|
||||
|
||||
<a id="1.73.0-Misc"></a>
|
||||
|
|
|
|||
|
|
@ -342,7 +342,7 @@ impl MetaItem {
|
|||
let span = span.with_hi(segments.last().unwrap().ident.span.hi());
|
||||
Path { span, segments, tokens: None }
|
||||
}
|
||||
Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. }, _)) => match &**nt {
|
||||
Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. }, _)) => match &nt.0 {
|
||||
token::Nonterminal::NtMeta(item) => return item.meta(item.path.span),
|
||||
token::Nonterminal::NtPath(path) => (**path).clone(),
|
||||
_ => return None,
|
||||
|
|
|
|||
|
|
@ -59,9 +59,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
|||
/// Requirements for a `StableHashingContext` to be used in this crate.
|
||||
/// This is a hack to allow using the `HashStable_Generic` derive macro
|
||||
/// instead of implementing everything in `rustc_middle`.
|
||||
pub trait HashStableContext:
|
||||
rustc_type_ir::HashStableContext + rustc_span::HashStableContext
|
||||
{
|
||||
pub trait HashStableContext: rustc_span::HashStableContext {
|
||||
fn hash_attr(&mut self, _: &ast::Attribute, hasher: &mut StableHasher);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -764,7 +764,10 @@ pub fn visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) {
|
|||
return; // Avoid visiting the span for the second time.
|
||||
}
|
||||
token::Interpolated(nt) => {
|
||||
visit_nonterminal(Lrc::make_mut(nt), vis);
|
||||
let nt = Lrc::make_mut(nt);
|
||||
let (nt, sp) = (&mut nt.0, &mut nt.1);
|
||||
vis.visit_span(sp);
|
||||
visit_nonterminal(nt, vis);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ impl Lit {
|
|||
Ident(name, false) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)),
|
||||
Literal(token_lit) => Some(token_lit),
|
||||
Interpolated(ref nt)
|
||||
if let NtExpr(expr) | NtLiteral(expr) = &**nt
|
||||
if let NtExpr(expr) | NtLiteral(expr) = &nt.0
|
||||
&& let ast::ExprKind::Lit(token_lit) = expr.kind =>
|
||||
{
|
||||
Some(token_lit)
|
||||
|
|
@ -314,7 +314,7 @@ pub enum TokenKind {
|
|||
/// - It prevents `Token` from implementing `Copy`.
|
||||
/// It adds complexity and likely slows things down. Please don't add new
|
||||
/// occurrences of this token kind!
|
||||
Interpolated(Lrc<Nonterminal>),
|
||||
Interpolated(Lrc<(Nonterminal, Span)>),
|
||||
|
||||
/// A doc comment token.
|
||||
/// `Symbol` is the doc comment's data excluding its "quotes" (`///`, `/**`, etc)
|
||||
|
|
@ -388,7 +388,8 @@ impl TokenKind {
|
|||
match *self {
|
||||
Comma => Some(vec![Dot, Lt, Semi]),
|
||||
Semi => Some(vec![Colon, Comma]),
|
||||
FatArrow => Some(vec![Eq, RArrow]),
|
||||
Colon => Some(vec![Semi]),
|
||||
FatArrow => Some(vec![Eq, RArrow, Ge, Gt]),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -421,7 +422,7 @@ impl Token {
|
|||
/// if they keep spans or perform edition checks.
|
||||
pub fn uninterpolated_span(&self) -> Span {
|
||||
match &self.kind {
|
||||
Interpolated(nt) => nt.span(),
|
||||
Interpolated(nt) => nt.0.use_span(),
|
||||
_ => self.span,
|
||||
}
|
||||
}
|
||||
|
|
@ -464,7 +465,7 @@ impl Token {
|
|||
ModSep | // global path
|
||||
Lifetime(..) | // labeled loop
|
||||
Pound => true, // expression attributes
|
||||
Interpolated(ref nt) => matches!(**nt, NtLiteral(..) |
|
||||
Interpolated(ref nt) => matches!(&nt.0, NtLiteral(..) |
|
||||
NtExpr(..) |
|
||||
NtBlock(..) |
|
||||
NtPath(..)),
|
||||
|
|
@ -488,7 +489,7 @@ impl Token {
|
|||
| DotDot | DotDotDot | DotDotEq // ranges
|
||||
| Lt | BinOp(Shl) // associated path
|
||||
| ModSep => true, // global path
|
||||
Interpolated(ref nt) => matches!(**nt, NtLiteral(..) |
|
||||
Interpolated(ref nt) => matches!(&nt.0, NtLiteral(..) |
|
||||
NtPat(..) |
|
||||
NtBlock(..) |
|
||||
NtPath(..)),
|
||||
|
|
@ -511,7 +512,7 @@ impl Token {
|
|||
Lifetime(..) | // lifetime bound in trait object
|
||||
Lt | BinOp(Shl) | // associated path
|
||||
ModSep => true, // global path
|
||||
Interpolated(ref nt) => matches!(**nt, NtTy(..) | NtPath(..)),
|
||||
Interpolated(ref nt) => matches!(&nt.0, NtTy(..) | NtPath(..)),
|
||||
// For anonymous structs or unions, which only appear in specific positions
|
||||
// (type of struct fields or union fields), we don't consider them as regular types
|
||||
_ => false,
|
||||
|
|
@ -522,7 +523,7 @@ impl Token {
|
|||
pub fn can_begin_const_arg(&self) -> bool {
|
||||
match self.kind {
|
||||
OpenDelim(Delimiter::Brace) => true,
|
||||
Interpolated(ref nt) => matches!(**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
|
||||
Interpolated(ref nt) => matches!(&nt.0, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
|
||||
_ => self.can_begin_literal_maybe_minus(),
|
||||
}
|
||||
}
|
||||
|
|
@ -576,7 +577,7 @@ impl Token {
|
|||
match self.uninterpolate().kind {
|
||||
Literal(..) | BinOp(Minus) => true,
|
||||
Ident(name, false) if name.is_bool_lit() => true,
|
||||
Interpolated(ref nt) => match &**nt {
|
||||
Interpolated(ref nt) => match &nt.0 {
|
||||
NtLiteral(_) => true,
|
||||
NtExpr(e) => match &e.kind {
|
||||
ast::ExprKind::Lit(_) => true,
|
||||
|
|
@ -597,9 +598,9 @@ impl Token {
|
|||
/// otherwise returns the original token.
|
||||
pub fn uninterpolate(&self) -> Cow<'_, Token> {
|
||||
match &self.kind {
|
||||
Interpolated(nt) => match **nt {
|
||||
Interpolated(nt) => match &nt.0 {
|
||||
NtIdent(ident, is_raw) => {
|
||||
Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span))
|
||||
Cow::Owned(Token::new(Ident(ident.name, *is_raw), ident.span))
|
||||
}
|
||||
NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)),
|
||||
_ => Cow::Borrowed(self),
|
||||
|
|
@ -614,8 +615,8 @@ impl Token {
|
|||
// We avoid using `Token::uninterpolate` here because it's slow.
|
||||
match &self.kind {
|
||||
&Ident(name, is_raw) => Some((Ident::new(name, self.span), is_raw)),
|
||||
Interpolated(nt) => match **nt {
|
||||
NtIdent(ident, is_raw) => Some((ident, is_raw)),
|
||||
Interpolated(nt) => match &nt.0 {
|
||||
NtIdent(ident, is_raw) => Some((*ident, *is_raw)),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
|
|
@ -628,8 +629,8 @@ impl Token {
|
|||
// We avoid using `Token::uninterpolate` here because it's slow.
|
||||
match &self.kind {
|
||||
&Lifetime(name) => Some(Ident::new(name, self.span)),
|
||||
Interpolated(nt) => match **nt {
|
||||
NtLifetime(ident) => Some(ident),
|
||||
Interpolated(nt) => match &nt.0 {
|
||||
NtLifetime(ident) => Some(*ident),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
|
|
@ -655,7 +656,7 @@ impl Token {
|
|||
/// Returns `true` if the token is an interpolated path.
|
||||
fn is_path(&self) -> bool {
|
||||
if let Interpolated(nt) = &self.kind
|
||||
&& let NtPath(..) = **nt
|
||||
&& let NtPath(..) = &nt.0
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -668,7 +669,7 @@ impl Token {
|
|||
/// (which happens while parsing the result of macro expansion)?
|
||||
pub fn is_whole_expr(&self) -> bool {
|
||||
if let Interpolated(nt) = &self.kind
|
||||
&& let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtBlock(_) = **nt
|
||||
&& let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtBlock(_) = &nt.0
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -679,7 +680,7 @@ impl Token {
|
|||
/// Is the token an interpolated block (`$b:block`)?
|
||||
pub fn is_whole_block(&self) -> bool {
|
||||
if let Interpolated(nt) = &self.kind
|
||||
&& let NtBlock(..) = **nt
|
||||
&& let NtBlock(..) = &nt.0
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -927,7 +928,7 @@ impl fmt::Display for NonterminalKind {
|
|||
}
|
||||
|
||||
impl Nonterminal {
|
||||
pub fn span(&self) -> Span {
|
||||
pub fn use_span(&self) -> Span {
|
||||
match self {
|
||||
NtItem(item) => item.span,
|
||||
NtBlock(block) => block.span,
|
||||
|
|
@ -941,6 +942,23 @@ impl Nonterminal {
|
|||
NtVis(vis) => vis.span,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn descr(&self) -> &'static str {
|
||||
match self {
|
||||
NtItem(..) => "item",
|
||||
NtBlock(..) => "block",
|
||||
NtStmt(..) => "statement",
|
||||
NtPat(..) => "pattern",
|
||||
NtExpr(..) => "expression",
|
||||
NtLiteral(..) => "literal",
|
||||
NtTy(..) => "type",
|
||||
NtIdent(..) => "identifier",
|
||||
NtLifetime(..) => "lifetime",
|
||||
NtMeta(..) => "attribute",
|
||||
NtPath(..) => "path",
|
||||
NtVis(..) => "visibility",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Nonterminal {
|
||||
|
|
|
|||
|
|
@ -477,13 +477,13 @@ impl TokenStream {
|
|||
|
||||
fn flatten_token(token: &Token, spacing: Spacing) -> TokenTree {
|
||||
match &token.kind {
|
||||
token::Interpolated(nt) if let token::NtIdent(ident, is_raw) = **nt => {
|
||||
token::Interpolated(nt) if let token::NtIdent(ident, is_raw) = nt.0 => {
|
||||
TokenTree::Token(Token::new(token::Ident(ident.name, is_raw), ident.span), spacing)
|
||||
}
|
||||
token::Interpolated(nt) => TokenTree::Delimited(
|
||||
DelimSpan::from_single(token.span),
|
||||
Delimiter::Invisible,
|
||||
TokenStream::from_nonterminal_ast(nt).flattened(),
|
||||
TokenStream::from_nonterminal_ast(&nt.0).flattened(),
|
||||
),
|
||||
_ => TokenTree::Token(token.clone(), spacing),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,8 +42,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
// Merge attributes into the inner expression.
|
||||
if !e.attrs.is_empty() {
|
||||
let old_attrs =
|
||||
self.attrs.get(&ex.hir_id.local_id).map(|la| *la).unwrap_or(&[]);
|
||||
let old_attrs = self.attrs.get(&ex.hir_id.local_id).copied().unwrap_or(&[]);
|
||||
self.attrs.insert(
|
||||
ex.hir_id.local_id,
|
||||
&*self.arena.alloc_from_iter(
|
||||
|
|
|
|||
|
|
@ -499,7 +499,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
/// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name
|
||||
/// resolver (if any).
|
||||
fn orig_opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
|
||||
self.resolver.node_id_to_def_id.get(&node).map(|local_def_id| *local_def_id)
|
||||
self.resolver.node_id_to_def_id.get(&node).copied()
|
||||
}
|
||||
|
||||
/// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name
|
||||
|
|
@ -542,7 +542,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
self.generics_def_id_map
|
||||
.iter()
|
||||
.rev()
|
||||
.find_map(|map| map.get(&local_def_id).map(|local_def_id| *local_def_id))
|
||||
.find_map(|map| map.get(&local_def_id).copied())
|
||||
.unwrap_or(local_def_id)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -825,7 +825,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
}
|
||||
token::Eof => "<eof>".into(),
|
||||
|
||||
token::Interpolated(ref nt) => self.nonterminal_to_string(nt).into(),
|
||||
token::Interpolated(ref nt) => self.nonterminal_to_string(&nt.0).into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1578,8 +1578,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
return;
|
||||
};
|
||||
let sig = args.as_closure().sig();
|
||||
let tupled_params =
|
||||
tcx.erase_late_bound_regions(sig.inputs().iter().next().unwrap().map_bound(|&b| b));
|
||||
let tupled_params = tcx.instantiate_bound_regions_with_erased(
|
||||
sig.inputs().iter().next().unwrap().map_bound(|&b| b),
|
||||
);
|
||||
let ty::Tuple(params) = tupled_params.kind() else { return };
|
||||
|
||||
// Find the first argument with a matching type, get its name
|
||||
|
|
|
|||
|
|
@ -5,12 +5,13 @@ use rustc_hir as hir;
|
|||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_index::IndexSlice;
|
||||
use rustc_infer::infer::NllRegionVariableOrigin;
|
||||
use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
|
||||
use rustc_middle::mir::{
|
||||
Body, CallSource, CastKind, ConstraintCategory, FakeReadCause, Local, LocalInfo, Location,
|
||||
Operand, Place, Rvalue, Statement, StatementKind, TerminatorKind,
|
||||
};
|
||||
use rustc_middle::ty::adjustment::PointerCoercion;
|
||||
use rustc_middle::ty::{self, RegionVid, TyCtxt};
|
||||
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
|
||||
use rustc_span::symbol::{kw, Symbol};
|
||||
use rustc_span::{sym, DesugaringKind, Span};
|
||||
use rustc_trait_selection::traits::error_reporting::FindExprBySpan;
|
||||
|
|
@ -290,12 +291,69 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
if let ConstraintCategory::Cast { unsize_to: Some(unsize_ty) } = category {
|
||||
self.add_object_lifetime_default_note(tcx, err, unsize_ty);
|
||||
}
|
||||
self.add_lifetime_bound_suggestion_to_diagnostic(err, &category, span, region_name);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_object_lifetime_default_note(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
unsize_ty: Ty<'tcx>,
|
||||
) {
|
||||
if let ty::Adt(def, args) = unsize_ty.kind() {
|
||||
// We try to elaborate the object lifetime defaults and present those to the user. This should
|
||||
// make it clear where the region constraint is coming from.
|
||||
let generics = tcx.generics_of(def.did());
|
||||
|
||||
let mut has_dyn = false;
|
||||
let mut failed = false;
|
||||
|
||||
let elaborated_args = std::iter::zip(*args, &generics.params).map(|(arg, param)| {
|
||||
if let Some(ty::Dynamic(obj, _, ty::DynKind::Dyn)) = arg.as_type().map(Ty::kind) {
|
||||
let default = tcx.object_lifetime_default(param.def_id);
|
||||
|
||||
let re_static = tcx.lifetimes.re_static;
|
||||
|
||||
let implied_region = match default {
|
||||
// This is not entirely precise.
|
||||
ObjectLifetimeDefault::Empty => re_static,
|
||||
ObjectLifetimeDefault::Ambiguous => {
|
||||
failed = true;
|
||||
re_static
|
||||
}
|
||||
ObjectLifetimeDefault::Param(param_def_id) => {
|
||||
let index = generics.param_def_id_to_index[¶m_def_id] as usize;
|
||||
args.get(index).and_then(|arg| arg.as_region()).unwrap_or_else(|| {
|
||||
failed = true;
|
||||
re_static
|
||||
})
|
||||
}
|
||||
ObjectLifetimeDefault::Static => re_static,
|
||||
};
|
||||
|
||||
has_dyn = true;
|
||||
|
||||
Ty::new_dynamic(tcx, obj, implied_region, ty::DynKind::Dyn).into()
|
||||
} else {
|
||||
arg
|
||||
}
|
||||
});
|
||||
let elaborated_ty = Ty::new_adt(tcx, *def, tcx.mk_args_from_iter(elaborated_args));
|
||||
|
||||
if has_dyn && !failed {
|
||||
err.note(format!(
|
||||
"due to object lifetime defaults, `{unsize_ty}` actually means `{elaborated_ty}`"
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_lifetime_bound_suggestion_to_diagnostic(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ use crate::session_diagnostics::{
|
|||
LifetimeReturnCategoryErr, RequireStaticErr, VarHereDenote,
|
||||
};
|
||||
|
||||
use super::{OutlivesSuggestionBuilder, RegionName};
|
||||
use super::{OutlivesSuggestionBuilder, RegionName, RegionNameSource};
|
||||
use crate::region_infer::{BlameConstraint, ExtraConstraintInfo};
|
||||
use crate::{
|
||||
nll::ConstraintDescription,
|
||||
|
|
@ -53,7 +53,7 @@ impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> {
|
|||
ConstraintCategory::Yield => "yielding this value ",
|
||||
ConstraintCategory::UseAsConst => "using this value as a constant ",
|
||||
ConstraintCategory::UseAsStatic => "using this value as a static ",
|
||||
ConstraintCategory::Cast => "cast ",
|
||||
ConstraintCategory::Cast { .. } => "cast ",
|
||||
ConstraintCategory::CallArgument(_) => "argument ",
|
||||
ConstraintCategory::TypeAnnotation => "type annotation ",
|
||||
ConstraintCategory::ClosureBounds => "closure body ",
|
||||
|
|
@ -763,7 +763,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
let err = LifetimeOutliveErr { span: *span };
|
||||
let mut diag = self.infcx.tcx.sess.create_err(err);
|
||||
|
||||
let fr_name = self.give_region_a_name(*fr).unwrap();
|
||||
// In certain scenarios, such as the one described in issue #118021,
|
||||
// we might encounter a lifetime that cannot be named.
|
||||
// These situations are bound to result in errors.
|
||||
// To prevent an immediate ICE, we opt to create a dummy name instead.
|
||||
let fr_name = self.give_region_a_name(*fr).unwrap_or(RegionName {
|
||||
name: kw::UnderscoreLifetime,
|
||||
source: RegionNameSource::Static,
|
||||
});
|
||||
fr_name.highlight_region_name(&mut diag);
|
||||
let outlived_fr_name = self.give_region_a_name(*outlived_fr).unwrap();
|
||||
outlived_fr_name.highlight_region_name(&mut diag);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use rustc_infer::infer::region_constraints::GenericKind;
|
|||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::traits::query::OutlivesBound;
|
||||
use rustc_middle::ty::{self, RegionVid, Ty};
|
||||
use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt};
|
||||
use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
|
||||
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
|
||||
use std::rc::Rc;
|
||||
|
|
@ -321,6 +321,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
|||
.map_err(|_: ErrorGuaranteed| debug!("failed to compute implied bounds {:?}", ty))
|
||||
.ok()?;
|
||||
debug!(?bounds, ?constraints);
|
||||
// Because of #109628, we may have unexpected placeholders. Ignore them!
|
||||
// FIXME(#109628): panic in this case once the issue is fixed.
|
||||
let bounds = bounds.into_iter().filter(|bound| !bound.has_placeholders());
|
||||
self.add_outlives_bounds(bounds);
|
||||
constraints
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1387,7 +1387,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
return;
|
||||
}
|
||||
};
|
||||
let (sig, map) = tcx.replace_late_bound_regions(sig, |br| {
|
||||
let (sig, map) = tcx.instantiate_bound_regions(sig, |br| {
|
||||
use crate::renumber::RegionCtxt;
|
||||
|
||||
let region_ctxt_fn = || {
|
||||
|
|
@ -1934,7 +1934,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
*ty,
|
||||
ty_fn_ptr_from,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast,
|
||||
ConstraintCategory::Cast { unsize_to: None },
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
|
|
@ -1959,7 +1959,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
*ty,
|
||||
ty_fn_ptr_from,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast,
|
||||
ConstraintCategory::Cast { unsize_to: None },
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
|
|
@ -1988,7 +1988,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
*ty,
|
||||
ty_fn_ptr_from,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast,
|
||||
ConstraintCategory::Cast { unsize_to: None },
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
|
|
@ -2013,7 +2013,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
self.prove_trait_ref(
|
||||
trait_ref,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast,
|
||||
ConstraintCategory::Cast {
|
||||
unsize_to: Some(tcx.fold_regions(ty, |r, _| {
|
||||
if let ty::ReVar(_) = r.kind() {
|
||||
tcx.lifetimes.re_erased
|
||||
} else {
|
||||
r
|
||||
}
|
||||
})),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -2033,7 +2041,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
.iter()
|
||||
.map(|predicate| predicate.with_self_ty(tcx, self_ty)),
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast,
|
||||
ConstraintCategory::Cast { unsize_to: None },
|
||||
);
|
||||
|
||||
let outlives_predicate = tcx.mk_predicate(Binder::dummy(
|
||||
|
|
@ -2044,7 +2052,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
self.prove_predicate(
|
||||
outlives_predicate,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast,
|
||||
ConstraintCategory::Cast { unsize_to: None },
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -2065,7 +2073,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
*ty_from,
|
||||
*ty_to,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast,
|
||||
ConstraintCategory::Cast { unsize_to: None },
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
|
|
@ -2131,7 +2139,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
*ty_elem,
|
||||
*ty_to,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast,
|
||||
ConstraintCategory::Cast { unsize_to: None },
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
|
|
|
|||
|
|
@ -738,13 +738,13 @@ trait InferCtxtExt<'tcx> {
|
|||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>;
|
||||
|
||||
fn replace_late_bound_regions_with_nll_infer_vars_in_recursive_scope(
|
||||
fn instantiate_bound_regions_with_nll_infer_vars_in_recursive_scope(
|
||||
&self,
|
||||
mir_def_id: LocalDefId,
|
||||
indices: &mut UniversalRegionIndices<'tcx>,
|
||||
);
|
||||
|
||||
fn replace_late_bound_regions_with_nll_infer_vars_in_item(
|
||||
fn instantiate_bound_regions_with_nll_infer_vars_in_item(
|
||||
&self,
|
||||
mir_def_id: LocalDefId,
|
||||
indices: &mut UniversalRegionIndices<'tcx>,
|
||||
|
|
@ -780,7 +780,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> {
|
|||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
let (value, _map) = self.tcx.replace_late_bound_regions(value, |br| {
|
||||
let (value, _map) = self.tcx.instantiate_bound_regions(value, |br| {
|
||||
debug!(?br);
|
||||
let liberated_region =
|
||||
ty::Region::new_late_param(self.tcx, all_outlive_scope.to_def_id(), br.kind);
|
||||
|
|
@ -810,7 +810,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> {
|
|||
/// set of late-bound regions and checks for any that we have not yet seen, adding them to the
|
||||
/// inputs vector.
|
||||
#[instrument(skip(self, indices))]
|
||||
fn replace_late_bound_regions_with_nll_infer_vars_in_recursive_scope(
|
||||
fn instantiate_bound_regions_with_nll_infer_vars_in_recursive_scope(
|
||||
&self,
|
||||
mir_def_id: LocalDefId,
|
||||
indices: &mut UniversalRegionIndices<'tcx>,
|
||||
|
|
@ -830,7 +830,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
#[instrument(skip(self, indices))]
|
||||
fn replace_late_bound_regions_with_nll_infer_vars_in_item(
|
||||
fn instantiate_bound_regions_with_nll_infer_vars_in_item(
|
||||
&self,
|
||||
mir_def_id: LocalDefId,
|
||||
indices: &mut UniversalRegionIndices<'tcx>,
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: CPU features
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: cat /proc/cpuinfo
|
||||
|
||||
- name: Cache cargo target dir
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
|
|
|
|||
|
|
@ -66,6 +66,10 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: CPU features
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: cat /proc/cpuinfo
|
||||
|
||||
- name: Cache cargo target dir
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
|
|
@ -136,6 +140,9 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: CPU features
|
||||
run: cat /proc/cpuinfo
|
||||
|
||||
- name: Prepare dependencies
|
||||
run: ./y.sh prepare
|
||||
|
||||
|
|
@ -159,6 +166,9 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: CPU features
|
||||
run: cat /proc/cpuinfo
|
||||
|
||||
- name: Cache cargo target dir
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: CPU features
|
||||
run: cat /proc/cpuinfo
|
||||
|
||||
- name: Cache cargo target dir
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
|
|
@ -31,6 +34,9 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: CPU features
|
||||
run: cat /proc/cpuinfo
|
||||
|
||||
- name: Cache cargo target dir
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
|
|
|
|||
|
|
@ -5,8 +5,48 @@ This has the potential to improve compilation times in debug mode.
|
|||
If your project doesn't use any of the things listed under "Not yet supported", it should work fine.
|
||||
If not please open an issue.
|
||||
|
||||
## Download using Rustup
|
||||
|
||||
The Cranelift codegen backend is distributed in nightly builds on Linux and x86_64 macOS. If you want to
|
||||
install it using Rustup, you can do that by running:
|
||||
|
||||
```bash
|
||||
$ rustup component add rustc-codegen-cranelift-preview --toolchain nightly
|
||||
```
|
||||
|
||||
Once it is installed, you can enable it with one of the following approaches:
|
||||
- `CARGO_PROFILE_DEV_CODEGEN_BACKEND=cranelift cargo +nightly build -Zcodegen-backend`
|
||||
- `RUSTFLAGS="-Zcodegen-backend=cranelift" cargo +nightly build`
|
||||
- Add the following to `.cargo/config.toml`:
|
||||
```toml
|
||||
[unstable]
|
||||
codegen-backend = true
|
||||
|
||||
[profile.dev]
|
||||
codegen-backend = "cranelift"
|
||||
```
|
||||
- Add the following to `Cargo.toml`:
|
||||
```toml
|
||||
# This line needs to come before anything else in Cargo.toml
|
||||
cargo-features = ["codegen-backend"]
|
||||
|
||||
[profile.dev]
|
||||
codegen-backend = "cranelift"
|
||||
```
|
||||
|
||||
## Precompiled builds
|
||||
|
||||
You can also download a pre-built version from the [releases] page.
|
||||
Extract the `dist` directory in the archive anywhere you want.
|
||||
If you want to use `cargo clif build` instead of having to specify the full path to the `cargo-clif` executable, you can add the `bin` subdirectory of the extracted `dist` directory to your `PATH`.
|
||||
(tutorial [for Windows](https://stackoverflow.com/a/44272417), and [for Linux/MacOS](https://unix.stackexchange.com/questions/26047/how-to-correctly-add-a-path-to-path/26059#26059)).
|
||||
|
||||
[releases]: https://github.com/rust-lang/rustc_codegen_cranelift/releases/tag/dev
|
||||
|
||||
## Building and testing
|
||||
|
||||
If you want to build the backend manually, you can download it from GitHub and build it yourself:
|
||||
|
||||
```bash
|
||||
$ git clone https://github.com/rust-lang/rustc_codegen_cranelift
|
||||
$ cd rustc_codegen_cranelift
|
||||
|
|
@ -22,15 +62,6 @@ $ ./test.sh
|
|||
|
||||
For more docs on how to build and test see [build_system/usage.txt](build_system/usage.txt) or the help message of `./y.sh`.
|
||||
|
||||
## Precompiled builds
|
||||
|
||||
Alternatively you can download a pre built version from the [releases] page.
|
||||
Extract the `dist` directory in the archive anywhere you want.
|
||||
If you want to use `cargo clif build` instead of having to specify the full path to the `cargo-clif` executable, you can add the `bin` subdirectory of the extracted `dist` directory to your `PATH`.
|
||||
(tutorial [for Windows](https://stackoverflow.com/a/44272417), and [for Linux/MacOS](https://unix.stackexchange.com/questions/26047/how-to-correctly-add-a-path-to-path/26059#26059)).
|
||||
|
||||
[releases]: https://github.com/rust-lang/rustc_codegen_cranelift/releases/tag/dev
|
||||
|
||||
## Usage
|
||||
|
||||
rustc_codegen_cranelift can be used as a near-drop-in replacement for `cargo build` or `cargo run` for existing projects.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2023-11-10"
|
||||
channel = "nightly-2023-11-16"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools"]
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ case $1 in
|
|||
git pull origin master
|
||||
branch=sync_cg_clif-$(date +%Y-%m-%d)
|
||||
git checkout -b "$branch"
|
||||
"$cg_clif/git-fixed-subtree.sh" pull --prefix=compiler/rustc_codegen_cranelift/ https://github.com/bjorn3/rustc_codegen_cranelift.git master
|
||||
"$cg_clif/git-fixed-subtree.sh" pull --prefix=compiler/rustc_codegen_cranelift/ https://github.com/rust-lang/rustc_codegen_cranelift.git master
|
||||
git push -u my "$branch"
|
||||
|
||||
# immediately merge the merge commit into cg_clif to prevent merge conflicts when syncing
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
# CG_CLIF_FORCE_GNU_AS will force usage of as instead of the LLVM backend of rustc as we
|
||||
# the LLVM backend isn't compiled in here.
|
||||
export CG_CLIF_FORCE_GNU_AS=1
|
||||
|
||||
# Compiletest expects all standard library paths to start with /rustc/FAKE_PREFIX.
|
||||
# CG_CLIF_STDLIB_REMAP_PATH_PREFIX will cause cg_clif's build system to pass
|
||||
# --remap-path-prefix to handle this.
|
||||
# CG_CLIF_FORCE_GNU_AS will force usage of as instead of the LLVM backend of rustc as we
|
||||
# the LLVM backend isn't compiled in here.
|
||||
CG_CLIF_FORCE_GNU_AS=1 CG_CLIF_STDLIB_REMAP_PATH_PREFIX=/rustc/FAKE_PREFIX ./y.sh build
|
||||
CG_CLIF_STDLIB_REMAP_PATH_PREFIX=/rustc/FAKE_PREFIX ./y.sh build
|
||||
|
||||
echo "[SETUP] Rust fork"
|
||||
git clone https://github.com/rust-lang/rust.git || true
|
||||
git clone https://github.com/rust-lang/rust.git --filter=tree:0 || true
|
||||
pushd rust
|
||||
git fetch
|
||||
git checkout -- .
|
||||
|
|
|
|||
|
|
@ -11,7 +11,5 @@ rm -r compiler/rustc_codegen_cranelift/{Cargo.*,src}
|
|||
cp ../Cargo.* compiler/rustc_codegen_cranelift/
|
||||
cp -r ../src compiler/rustc_codegen_cranelift/src
|
||||
|
||||
# CG_CLIF_FORCE_GNU_AS will force usage of as instead of the LLVM backend of rustc as we
|
||||
# the LLVM backend isn't compiled in here.
|
||||
CG_CLIF_FORCE_GNU_AS=1 ./x.py build --stage 1 library/std
|
||||
./x.py build --stage 1 library/std
|
||||
popd
|
||||
|
|
|
|||
|
|
@ -383,6 +383,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
|
|||
args,
|
||||
ret_place,
|
||||
target,
|
||||
source_info.span,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -456,7 +456,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
|||
);
|
||||
}
|
||||
|
||||
crate::inline_asm::codegen_inline_asm(
|
||||
crate::inline_asm::codegen_inline_asm_terminator(
|
||||
fx,
|
||||
source_info.span,
|
||||
template,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
//! Handling of `static`s, `const`s and promoted allocations
|
||||
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use cranelift_module::*;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::mir::interpret::{read_target_uint, AllocId, GlobalAlloc, Scalar};
|
||||
use rustc_middle::mir::ConstValue;
|
||||
use rustc_middle::ty::ScalarInt;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
|
|
@ -430,9 +433,9 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
|
|||
pub(crate) fn mir_operand_get_const_val<'tcx>(
|
||||
fx: &FunctionCx<'_, '_, 'tcx>,
|
||||
operand: &Operand<'tcx>,
|
||||
) -> Option<ConstValue<'tcx>> {
|
||||
) -> Option<ScalarInt> {
|
||||
match operand {
|
||||
Operand::Constant(const_) => Some(eval_mir_constant(fx, const_).0),
|
||||
Operand::Constant(const_) => eval_mir_constant(fx, const_).0.try_to_scalar_int(),
|
||||
// FIXME(rust-lang/rust#85105): Casts like `IMM8 as u32` result in the const being stored
|
||||
// inside a temporary before being passed to the intrinsic requiring the const argument.
|
||||
// This code tries to find a single constant defining definition of the referenced local.
|
||||
|
|
@ -440,7 +443,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
|
|||
if !place.projection.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let mut computed_const_val = None;
|
||||
let mut computed_scalar_int = None;
|
||||
for bb_data in fx.mir.basic_blocks.iter() {
|
||||
for stmt in &bb_data.statements {
|
||||
match &stmt.kind {
|
||||
|
|
@ -456,22 +459,38 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
|
|||
operand,
|
||||
ty,
|
||||
) => {
|
||||
if computed_const_val.is_some() {
|
||||
if computed_scalar_int.is_some() {
|
||||
return None; // local assigned twice
|
||||
}
|
||||
if !matches!(ty.kind(), ty::Uint(_) | ty::Int(_)) {
|
||||
return None;
|
||||
}
|
||||
let const_val = mir_operand_get_const_val(fx, operand)?;
|
||||
if fx.layout_of(*ty).size
|
||||
!= const_val.try_to_scalar_int()?.size()
|
||||
let scalar_int = mir_operand_get_const_val(fx, operand)?;
|
||||
let scalar_int = match fx
|
||||
.layout_of(*ty)
|
||||
.size
|
||||
.cmp(&scalar_int.size())
|
||||
{
|
||||
return None;
|
||||
}
|
||||
computed_const_val = Some(const_val);
|
||||
Ordering::Equal => scalar_int,
|
||||
Ordering::Less => match ty.kind() {
|
||||
ty::Uint(_) => ScalarInt::try_from_uint(
|
||||
scalar_int.try_to_uint(scalar_int.size()).unwrap(),
|
||||
fx.layout_of(*ty).size,
|
||||
)
|
||||
.unwrap(),
|
||||
ty::Int(_) => ScalarInt::try_from_int(
|
||||
scalar_int.try_to_int(scalar_int.size()).unwrap(),
|
||||
fx.layout_of(*ty).size,
|
||||
)
|
||||
.unwrap(),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Ordering::Greater => return None,
|
||||
};
|
||||
computed_scalar_int = Some(scalar_int);
|
||||
}
|
||||
Rvalue::Use(operand) => {
|
||||
computed_const_val = mir_operand_get_const_val(fx, operand)
|
||||
computed_scalar_int = mir_operand_get_const_val(fx, operand)
|
||||
}
|
||||
_ => return None,
|
||||
}
|
||||
|
|
@ -522,7 +541,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
|
|||
TerminatorKind::Call { .. } => {}
|
||||
}
|
||||
}
|
||||
computed_const_val
|
||||
computed_scalar_int
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use target_lexicon::BinaryFormat;
|
|||
|
||||
use crate::prelude::*;
|
||||
|
||||
enum CInlineAsmOperand<'tcx> {
|
||||
pub(crate) enum CInlineAsmOperand<'tcx> {
|
||||
In {
|
||||
reg: InlineAsmRegOrRegClass,
|
||||
value: Value,
|
||||
|
|
@ -34,7 +34,7 @@ enum CInlineAsmOperand<'tcx> {
|
|||
},
|
||||
}
|
||||
|
||||
pub(crate) fn codegen_inline_asm<'tcx>(
|
||||
pub(crate) fn codegen_inline_asm_terminator<'tcx>(
|
||||
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
||||
span: Span,
|
||||
template: &[InlineAsmTemplatePiece],
|
||||
|
|
@ -42,8 +42,6 @@ pub(crate) fn codegen_inline_asm<'tcx>(
|
|||
options: InlineAsmOptions,
|
||||
destination: Option<mir::BasicBlock>,
|
||||
) {
|
||||
// FIXME add .eh_frame unwind info directives
|
||||
|
||||
// Used by panic_abort on Windows, but uses a syntax which only happens to work with
|
||||
// asm!() by accident and breaks with the GNU assembler as well as global_asm!() for
|
||||
// the LLVM backend.
|
||||
|
|
@ -135,15 +133,33 @@ pub(crate) fn codegen_inline_asm<'tcx>(
|
|||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut inputs = Vec::new();
|
||||
let mut outputs = Vec::new();
|
||||
codegen_inline_asm_inner(fx, template, &operands, options);
|
||||
|
||||
match destination {
|
||||
Some(destination) => {
|
||||
let destination_block = fx.get_block(destination);
|
||||
fx.bcx.ins().jump(destination_block, &[]);
|
||||
}
|
||||
None => {
|
||||
fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn codegen_inline_asm_inner<'tcx>(
|
||||
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
||||
template: &[InlineAsmTemplatePiece],
|
||||
operands: &[CInlineAsmOperand<'tcx>],
|
||||
options: InlineAsmOptions,
|
||||
) {
|
||||
// FIXME add .eh_frame unwind info directives
|
||||
|
||||
let mut asm_gen = InlineAssemblyGenerator {
|
||||
tcx: fx.tcx,
|
||||
arch: fx.tcx.sess.asm_arch.unwrap(),
|
||||
enclosing_def_id: fx.instance.def_id(),
|
||||
template,
|
||||
operands: &operands,
|
||||
operands,
|
||||
options,
|
||||
registers: Vec::new(),
|
||||
stack_slots_clobber: Vec::new(),
|
||||
|
|
@ -165,6 +181,8 @@ pub(crate) fn codegen_inline_asm<'tcx>(
|
|||
let generated_asm = asm_gen.generate_asm_wrapper(&asm_name);
|
||||
fx.cx.global_asm.push_str(&generated_asm);
|
||||
|
||||
let mut inputs = Vec::new();
|
||||
let mut outputs = Vec::new();
|
||||
for (i, operand) in operands.iter().enumerate() {
|
||||
match operand {
|
||||
CInlineAsmOperand::In { reg: _, value } => {
|
||||
|
|
@ -186,16 +204,6 @@ pub(crate) fn codegen_inline_asm<'tcx>(
|
|||
}
|
||||
|
||||
call_inline_asm(fx, &asm_name, asm_gen.stack_slot_size, inputs, outputs);
|
||||
|
||||
match destination {
|
||||
Some(destination) => {
|
||||
let destination_block = fx.get_block(destination);
|
||||
fx.bcx.ins().jump(destination_block, &[]);
|
||||
}
|
||||
None => {
|
||||
fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct InlineAssemblyGenerator<'a, 'tcx> {
|
||||
|
|
@ -637,8 +645,21 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
|
|||
) {
|
||||
match arch {
|
||||
InlineAsmArch::X86_64 => {
|
||||
write!(generated_asm, " mov [rbx+0x{:x}], ", offset.bytes()).unwrap();
|
||||
reg.emit(generated_asm, InlineAsmArch::X86_64, None).unwrap();
|
||||
match reg {
|
||||
InlineAsmReg::X86(reg)
|
||||
if reg as u32 >= X86InlineAsmReg::xmm0 as u32
|
||||
&& reg as u32 <= X86InlineAsmReg::xmm15 as u32 =>
|
||||
{
|
||||
// rustc emits x0 rather than xmm0
|
||||
write!(generated_asm, " movups [rbx+0x{:x}], ", offset.bytes()).unwrap();
|
||||
write!(generated_asm, "xmm{}", reg as u32 - X86InlineAsmReg::xmm0 as u32)
|
||||
.unwrap();
|
||||
}
|
||||
_ => {
|
||||
write!(generated_asm, " mov [rbx+0x{:x}], ", offset.bytes()).unwrap();
|
||||
reg.emit(generated_asm, InlineAsmArch::X86_64, None).unwrap();
|
||||
}
|
||||
}
|
||||
generated_asm.push('\n');
|
||||
}
|
||||
InlineAsmArch::AArch64 => {
|
||||
|
|
@ -663,8 +684,24 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
|
|||
) {
|
||||
match arch {
|
||||
InlineAsmArch::X86_64 => {
|
||||
generated_asm.push_str(" mov ");
|
||||
reg.emit(generated_asm, InlineAsmArch::X86_64, None).unwrap();
|
||||
match reg {
|
||||
InlineAsmReg::X86(reg)
|
||||
if reg as u32 >= X86InlineAsmReg::xmm0 as u32
|
||||
&& reg as u32 <= X86InlineAsmReg::xmm15 as u32 =>
|
||||
{
|
||||
// rustc emits x0 rather than xmm0
|
||||
write!(
|
||||
generated_asm,
|
||||
" movups xmm{}",
|
||||
reg as u32 - X86InlineAsmReg::xmm0 as u32
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
_ => {
|
||||
generated_asm.push_str(" mov ");
|
||||
reg.emit(generated_asm, InlineAsmArch::X86_64, None).unwrap()
|
||||
}
|
||||
}
|
||||
writeln!(generated_asm, ", [rbx+0x{:x}]", offset.bytes()).unwrap();
|
||||
}
|
||||
InlineAsmArch::AArch64 => {
|
||||
|
|
@ -720,7 +757,12 @@ fn call_inline_asm<'tcx>(
|
|||
fx.bcx.ins().call(inline_asm_func, &[stack_slot_addr]);
|
||||
|
||||
for (offset, place) in outputs {
|
||||
let ty = fx.clif_type(place.layout().ty).unwrap();
|
||||
let ty = if place.layout().ty.is_simd() {
|
||||
let (lane_count, lane_type) = place.layout().ty.simd_size_and_type(fx.tcx);
|
||||
fx.clif_type(lane_type).unwrap().by(lane_count.try_into().unwrap()).unwrap()
|
||||
} else {
|
||||
fx.clif_type(place.layout().ty).unwrap()
|
||||
};
|
||||
let value = stack_slot.offset(fx, i32::try_from(offset.bytes()).unwrap().into()).load(
|
||||
fx,
|
||||
ty,
|
||||
|
|
@ -729,83 +771,3 @@ fn call_inline_asm<'tcx>(
|
|||
place.write_cvalue(fx, CValue::by_val(value, place.layout()));
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn codegen_xgetbv<'tcx>(
|
||||
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
||||
xcr_no: Value,
|
||||
ret: CPlace<'tcx>,
|
||||
) {
|
||||
// FIXME add .eh_frame unwind info directives
|
||||
|
||||
let operands = vec![
|
||||
CInlineAsmOperand::In {
|
||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::cx)),
|
||||
value: xcr_no,
|
||||
},
|
||||
CInlineAsmOperand::Out {
|
||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax)),
|
||||
late: true,
|
||||
place: Some(ret),
|
||||
},
|
||||
CInlineAsmOperand::Out {
|
||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx)),
|
||||
late: true,
|
||||
place: None,
|
||||
},
|
||||
];
|
||||
let options = InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM;
|
||||
|
||||
let mut inputs = Vec::new();
|
||||
let mut outputs = Vec::new();
|
||||
|
||||
let mut asm_gen = InlineAssemblyGenerator {
|
||||
tcx: fx.tcx,
|
||||
arch: fx.tcx.sess.asm_arch.unwrap(),
|
||||
enclosing_def_id: fx.instance.def_id(),
|
||||
template: &[InlineAsmTemplatePiece::String(
|
||||
"
|
||||
xgetbv
|
||||
// out = rdx << 32 | rax
|
||||
shl rdx, 32
|
||||
or rax, rdx
|
||||
"
|
||||
.to_string(),
|
||||
)],
|
||||
operands: &operands,
|
||||
options,
|
||||
registers: Vec::new(),
|
||||
stack_slots_clobber: Vec::new(),
|
||||
stack_slots_input: Vec::new(),
|
||||
stack_slots_output: Vec::new(),
|
||||
stack_slot_size: Size::from_bytes(0),
|
||||
};
|
||||
asm_gen.allocate_registers();
|
||||
asm_gen.allocate_stack_slots();
|
||||
|
||||
let inline_asm_index = fx.cx.inline_asm_index.get();
|
||||
fx.cx.inline_asm_index.set(inline_asm_index + 1);
|
||||
let asm_name = format!(
|
||||
"__inline_asm_{}_n{}",
|
||||
fx.cx.cgu_name.as_str().replace('.', "__").replace('-', "_"),
|
||||
inline_asm_index
|
||||
);
|
||||
|
||||
let generated_asm = asm_gen.generate_asm_wrapper(&asm_name);
|
||||
fx.cx.global_asm.push_str(&generated_asm);
|
||||
|
||||
for (i, operand) in operands.iter().enumerate() {
|
||||
match operand {
|
||||
CInlineAsmOperand::In { reg: _, value } => {
|
||||
inputs.push((asm_gen.stack_slots_input[i].unwrap(), *value));
|
||||
}
|
||||
CInlineAsmOperand::Out { reg: _, late: _, place } => {
|
||||
if let Some(place) = place {
|
||||
outputs.push((asm_gen.stack_slots_output[i].unwrap(), *place));
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
call_inline_asm(fx, &asm_name, asm_gen.stack_slot_size, inputs, outputs);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
|
|||
args: &[mir::Operand<'tcx>],
|
||||
ret: CPlace<'tcx>,
|
||||
target: Option<BasicBlock>,
|
||||
span: Span,
|
||||
) {
|
||||
if intrinsic.starts_with("llvm.aarch64") {
|
||||
return llvm_aarch64::codegen_aarch64_llvm_intrinsic_call(
|
||||
|
|
@ -31,6 +32,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
|
|||
args,
|
||||
ret,
|
||||
target,
|
||||
span,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
//! Emulate x86 LLVM intrinsics
|
||||
|
||||
use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||
use rustc_middle::ty::GenericArgsRef;
|
||||
use rustc_target::asm::*;
|
||||
|
||||
use crate::inline_asm::{codegen_inline_asm_inner, CInlineAsmOperand};
|
||||
use crate::intrinsics::*;
|
||||
use crate::prelude::*;
|
||||
|
||||
|
|
@ -12,6 +15,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
|
|||
args: &[mir::Operand<'tcx>],
|
||||
ret: CPlace<'tcx>,
|
||||
target: Option<BasicBlock>,
|
||||
span: Span,
|
||||
) {
|
||||
match intrinsic {
|
||||
"llvm.x86.sse2.pause" | "llvm.aarch64.isb" => {
|
||||
|
|
@ -24,7 +28,35 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
|
|||
|
||||
let xcr_no = xcr_no.load_scalar(fx);
|
||||
|
||||
crate::inline_asm::codegen_xgetbv(fx, xcr_no, ret);
|
||||
codegen_inline_asm_inner(
|
||||
fx,
|
||||
&[InlineAsmTemplatePiece::String(
|
||||
"
|
||||
xgetbv
|
||||
// out = rdx << 32 | rax
|
||||
shl rdx, 32
|
||||
or rax, rdx
|
||||
"
|
||||
.to_string(),
|
||||
)],
|
||||
&[
|
||||
CInlineAsmOperand::In {
|
||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::cx)),
|
||||
value: xcr_no,
|
||||
},
|
||||
CInlineAsmOperand::Out {
|
||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax)),
|
||||
late: true,
|
||||
place: Some(ret),
|
||||
},
|
||||
CInlineAsmOperand::Out {
|
||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx)),
|
||||
late: true,
|
||||
place: None,
|
||||
},
|
||||
],
|
||||
InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM,
|
||||
);
|
||||
}
|
||||
|
||||
"llvm.x86.sse3.ldu.dq" | "llvm.x86.avx.ldu.dq.256" => {
|
||||
|
|
@ -688,64 +720,278 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
|
|||
|
||||
"llvm.x86.pclmulqdq" => {
|
||||
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_clmulepi64_si128&ig_expand=772
|
||||
intrinsic_args!(fx, args => (a, b, imm8); intrinsic);
|
||||
intrinsic_args!(fx, args => (a, b, _imm8); intrinsic);
|
||||
|
||||
assert_eq!(a.layout(), b.layout());
|
||||
let layout = a.layout();
|
||||
let a = a.load_scalar(fx);
|
||||
let b = b.load_scalar(fx);
|
||||
|
||||
let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
|
||||
let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
|
||||
assert_eq!(lane_ty, fx.tcx.types.i64);
|
||||
assert_eq!(ret_lane_ty, fx.tcx.types.i64);
|
||||
assert_eq!(lane_count, 2);
|
||||
assert_eq!(ret_lane_count, 2);
|
||||
let imm8 = if let Some(imm8) = crate::constant::mir_operand_get_const_val(fx, &args[2])
|
||||
{
|
||||
imm8
|
||||
} else {
|
||||
fx.tcx.sess.span_fatal(
|
||||
span,
|
||||
"Index argument for `_mm_clmulepi64_si128` is not a constant",
|
||||
);
|
||||
};
|
||||
|
||||
let imm8 = imm8.load_scalar(fx);
|
||||
let imm8 = imm8.try_to_u8().unwrap_or_else(|_| panic!("kind not scalar: {:?}", imm8));
|
||||
|
||||
let control0 = fx.bcx.ins().band_imm(imm8, 0b0000_0001);
|
||||
let a_lane0 = a.value_lane(fx, 0).load_scalar(fx);
|
||||
let a_lane1 = a.value_lane(fx, 1).load_scalar(fx);
|
||||
let temp1 = fx.bcx.ins().select(control0, a_lane1, a_lane0);
|
||||
codegen_inline_asm_inner(
|
||||
fx,
|
||||
&[InlineAsmTemplatePiece::String(format!("pclmulqdq xmm0, xmm1, {imm8}"))],
|
||||
&[
|
||||
CInlineAsmOperand::InOut {
|
||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)),
|
||||
_late: true,
|
||||
in_value: a,
|
||||
out_place: Some(ret),
|
||||
},
|
||||
CInlineAsmOperand::In {
|
||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)),
|
||||
value: b,
|
||||
},
|
||||
],
|
||||
InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM,
|
||||
);
|
||||
}
|
||||
|
||||
let control4 = fx.bcx.ins().band_imm(imm8, 0b0001_0000);
|
||||
let b_lane0 = b.value_lane(fx, 0).load_scalar(fx);
|
||||
let b_lane1 = b.value_lane(fx, 1).load_scalar(fx);
|
||||
let temp2 = fx.bcx.ins().select(control4, b_lane1, b_lane0);
|
||||
"llvm.x86.aesni.aeskeygenassist" => {
|
||||
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aeskeygenassist_si128&ig_expand=261
|
||||
intrinsic_args!(fx, args => (a, _imm8); intrinsic);
|
||||
|
||||
fn extract_bit(fx: &mut FunctionCx<'_, '_, '_>, val: Value, bit: i64) -> Value {
|
||||
let tmp = fx.bcx.ins().ushr_imm(val, bit);
|
||||
fx.bcx.ins().band_imm(tmp, 1)
|
||||
}
|
||||
let a = a.load_scalar(fx);
|
||||
|
||||
let mut res1 = fx.bcx.ins().iconst(types::I64, 0);
|
||||
for i in 0..=63 {
|
||||
let x = extract_bit(fx, temp1, 0);
|
||||
let y = extract_bit(fx, temp2, i);
|
||||
let mut temp = fx.bcx.ins().band(x, y);
|
||||
for j in 1..=i {
|
||||
let x = extract_bit(fx, temp1, j);
|
||||
let y = extract_bit(fx, temp2, i - j);
|
||||
let z = fx.bcx.ins().band(x, y);
|
||||
temp = fx.bcx.ins().bxor(temp, z);
|
||||
}
|
||||
let temp = fx.bcx.ins().ishl_imm(temp, i);
|
||||
res1 = fx.bcx.ins().bor(res1, temp);
|
||||
}
|
||||
ret.place_lane(fx, 0).to_ptr().store(fx, res1, MemFlags::trusted());
|
||||
let imm8 = if let Some(imm8) = crate::constant::mir_operand_get_const_val(fx, &args[1])
|
||||
{
|
||||
imm8
|
||||
} else {
|
||||
fx.tcx.sess.span_fatal(
|
||||
span,
|
||||
"Index argument for `_mm_aeskeygenassist_si128` is not a constant",
|
||||
);
|
||||
};
|
||||
|
||||
let mut res2 = fx.bcx.ins().iconst(types::I64, 0);
|
||||
for i in 64..=127 {
|
||||
let mut temp = fx.bcx.ins().iconst(types::I64, 0);
|
||||
for j in i - 63..=63 {
|
||||
let x = extract_bit(fx, temp1, j);
|
||||
let y = extract_bit(fx, temp2, i - j);
|
||||
let z = fx.bcx.ins().band(x, y);
|
||||
temp = fx.bcx.ins().bxor(temp, z);
|
||||
}
|
||||
let temp = fx.bcx.ins().ishl_imm(temp, i);
|
||||
res2 = fx.bcx.ins().bor(res2, temp);
|
||||
}
|
||||
ret.place_lane(fx, 1).to_ptr().store(fx, res2, MemFlags::trusted());
|
||||
let imm8 = imm8.try_to_u8().unwrap_or_else(|_| panic!("kind not scalar: {:?}", imm8));
|
||||
|
||||
codegen_inline_asm_inner(
|
||||
fx,
|
||||
&[InlineAsmTemplatePiece::String(format!("aeskeygenassist xmm0, xmm0, {imm8}"))],
|
||||
&[CInlineAsmOperand::InOut {
|
||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)),
|
||||
_late: true,
|
||||
in_value: a,
|
||||
out_place: Some(ret),
|
||||
}],
|
||||
InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM,
|
||||
);
|
||||
}
|
||||
|
||||
"llvm.x86.aesni.aesimc" => {
|
||||
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesimc_si128&ig_expand=260
|
||||
intrinsic_args!(fx, args => (a); intrinsic);
|
||||
|
||||
let a = a.load_scalar(fx);
|
||||
|
||||
codegen_inline_asm_inner(
|
||||
fx,
|
||||
&[InlineAsmTemplatePiece::String("aesimc xmm0, xmm0".to_string())],
|
||||
&[CInlineAsmOperand::InOut {
|
||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)),
|
||||
_late: true,
|
||||
in_value: a,
|
||||
out_place: Some(ret),
|
||||
}],
|
||||
InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM,
|
||||
);
|
||||
}
|
||||
|
||||
"llvm.x86.aesni.aesenc" => {
|
||||
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesenc_si128&ig_expand=252
|
||||
intrinsic_args!(fx, args => (a, round_key); intrinsic);
|
||||
|
||||
let a = a.load_scalar(fx);
|
||||
let round_key = round_key.load_scalar(fx);
|
||||
|
||||
codegen_inline_asm_inner(
|
||||
fx,
|
||||
&[InlineAsmTemplatePiece::String("aesenc xmm0, xmm1".to_string())],
|
||||
&[
|
||||
CInlineAsmOperand::InOut {
|
||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)),
|
||||
_late: true,
|
||||
in_value: a,
|
||||
out_place: Some(ret),
|
||||
},
|
||||
CInlineAsmOperand::In {
|
||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)),
|
||||
value: round_key,
|
||||
},
|
||||
],
|
||||
InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM,
|
||||
);
|
||||
}
|
||||
|
||||
"llvm.x86.aesni.aesenclast" => {
|
||||
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesenclast_si128&ig_expand=257
|
||||
intrinsic_args!(fx, args => (a, round_key); intrinsic);
|
||||
|
||||
let a = a.load_scalar(fx);
|
||||
let round_key = round_key.load_scalar(fx);
|
||||
|
||||
codegen_inline_asm_inner(
|
||||
fx,
|
||||
&[InlineAsmTemplatePiece::String("aesenclast xmm0, xmm1".to_string())],
|
||||
&[
|
||||
CInlineAsmOperand::InOut {
|
||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)),
|
||||
_late: true,
|
||||
in_value: a,
|
||||
out_place: Some(ret),
|
||||
},
|
||||
CInlineAsmOperand::In {
|
||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)),
|
||||
value: round_key,
|
||||
},
|
||||
],
|
||||
InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM,
|
||||
);
|
||||
}
|
||||
|
||||
"llvm.x86.aesni.aesdec" => {
|
||||
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdec_si128&ig_expand=242
|
||||
intrinsic_args!(fx, args => (a, round_key); intrinsic);
|
||||
|
||||
let a = a.load_scalar(fx);
|
||||
let round_key = round_key.load_scalar(fx);
|
||||
|
||||
codegen_inline_asm_inner(
|
||||
fx,
|
||||
&[InlineAsmTemplatePiece::String("aesdec xmm0, xmm1".to_string())],
|
||||
&[
|
||||
CInlineAsmOperand::InOut {
|
||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)),
|
||||
_late: true,
|
||||
in_value: a,
|
||||
out_place: Some(ret),
|
||||
},
|
||||
CInlineAsmOperand::In {
|
||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)),
|
||||
value: round_key,
|
||||
},
|
||||
],
|
||||
InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM,
|
||||
);
|
||||
}
|
||||
|
||||
"llvm.x86.aesni.aesdeclast" => {
|
||||
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdeclast_si128&ig_expand=247
|
||||
intrinsic_args!(fx, args => (a, round_key); intrinsic);
|
||||
|
||||
let a = a.load_scalar(fx);
|
||||
let round_key = round_key.load_scalar(fx);
|
||||
|
||||
codegen_inline_asm_inner(
|
||||
fx,
|
||||
&[InlineAsmTemplatePiece::String("aesdeclast xmm0, xmm1".to_string())],
|
||||
&[
|
||||
CInlineAsmOperand::InOut {
|
||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)),
|
||||
_late: true,
|
||||
in_value: a,
|
||||
out_place: Some(ret),
|
||||
},
|
||||
CInlineAsmOperand::In {
|
||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)),
|
||||
value: round_key,
|
||||
},
|
||||
],
|
||||
InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM,
|
||||
);
|
||||
}
|
||||
|
||||
"llvm.x86.sha256rnds2" => {
|
||||
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sha256rnds2_epu32&ig_expand=5977
|
||||
intrinsic_args!(fx, args => (a, b, k); intrinsic);
|
||||
|
||||
let a = a.load_scalar(fx);
|
||||
let b = b.load_scalar(fx);
|
||||
let k = k.load_scalar(fx);
|
||||
|
||||
codegen_inline_asm_inner(
|
||||
fx,
|
||||
&[InlineAsmTemplatePiece::String("sha256rnds2 xmm1, xmm2".to_string())],
|
||||
&[
|
||||
CInlineAsmOperand::InOut {
|
||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)),
|
||||
_late: true,
|
||||
in_value: a,
|
||||
out_place: Some(ret),
|
||||
},
|
||||
CInlineAsmOperand::In {
|
||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm2)),
|
||||
value: b,
|
||||
},
|
||||
// Implicit argument to the sha256rnds2 instruction
|
||||
CInlineAsmOperand::In {
|
||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)),
|
||||
value: k,
|
||||
},
|
||||
],
|
||||
InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM,
|
||||
);
|
||||
}
|
||||
|
||||
"llvm.x86.sha256msg1" => {
|
||||
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sha256msg1_epu32&ig_expand=5975
|
||||
intrinsic_args!(fx, args => (a, b); intrinsic);
|
||||
|
||||
let a = a.load_scalar(fx);
|
||||
let b = b.load_scalar(fx);
|
||||
|
||||
codegen_inline_asm_inner(
|
||||
fx,
|
||||
&[InlineAsmTemplatePiece::String("sha256msg1 xmm1, xmm2".to_string())],
|
||||
&[
|
||||
CInlineAsmOperand::InOut {
|
||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)),
|
||||
_late: true,
|
||||
in_value: a,
|
||||
out_place: Some(ret),
|
||||
},
|
||||
CInlineAsmOperand::In {
|
||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm2)),
|
||||
value: b,
|
||||
},
|
||||
],
|
||||
InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM,
|
||||
);
|
||||
}
|
||||
|
||||
"llvm.x86.sha256msg2" => {
|
||||
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sha256msg2_epu32&ig_expand=5976
|
||||
intrinsic_args!(fx, args => (a, b); intrinsic);
|
||||
|
||||
let a = a.load_scalar(fx);
|
||||
let b = b.load_scalar(fx);
|
||||
|
||||
codegen_inline_asm_inner(
|
||||
fx,
|
||||
&[InlineAsmTemplatePiece::String("sha256msg2 xmm1, xmm2".to_string())],
|
||||
&[
|
||||
CInlineAsmOperand::InOut {
|
||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)),
|
||||
_late: true,
|
||||
in_value: a,
|
||||
out_place: Some(ret),
|
||||
},
|
||||
CInlineAsmOperand::In {
|
||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm2)),
|
||||
value: b,
|
||||
},
|
||||
],
|
||||
InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM,
|
||||
);
|
||||
}
|
||||
|
||||
"llvm.x86.avx.ptestz.256" => {
|
||||
|
|
|
|||
|
|
@ -282,11 +282,11 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||
fx.tcx.sess.span_fatal(span, "Index argument for `simd_insert` is not a constant");
|
||||
};
|
||||
|
||||
let idx = idx_const
|
||||
.try_to_bits(Size::from_bytes(4 /* u32*/))
|
||||
.unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const));
|
||||
let idx: u32 = idx_const
|
||||
.try_to_u32()
|
||||
.unwrap_or_else(|_| panic!("kind not scalar: {:?}", idx_const));
|
||||
let (lane_count, _lane_ty) = base.layout().ty.simd_size_and_type(fx.tcx);
|
||||
if idx >= lane_count.into() {
|
||||
if u64::from(idx) >= lane_count {
|
||||
fx.tcx.sess.span_fatal(
|
||||
fx.mir.span,
|
||||
format!("[simd_insert] idx {} >= lane_count {}", idx, lane_count),
|
||||
|
|
@ -331,10 +331,10 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||
};
|
||||
|
||||
let idx = idx_const
|
||||
.try_to_bits(Size::from_bytes(4 /* u32*/))
|
||||
.unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const));
|
||||
.try_to_u32()
|
||||
.unwrap_or_else(|_| panic!("kind not scalar: {:?}", idx_const));
|
||||
let (lane_count, _lane_ty) = v.layout().ty.simd_size_and_type(fx.tcx);
|
||||
if idx >= lane_count.into() {
|
||||
if u64::from(idx) >= lane_count {
|
||||
fx.tcx.sess.span_fatal(
|
||||
fx.mir.span,
|
||||
format!("[simd_extract] idx {} >= lane_count {}", idx, lane_count),
|
||||
|
|
|
|||
|
|
@ -99,8 +99,10 @@ jobs:
|
|||
- name: Build
|
||||
run: |
|
||||
./y.sh prepare --only-libcore
|
||||
./y.sh build
|
||||
cargo test
|
||||
# TODO: remove --features master when it is back to the default.
|
||||
./y.sh build --features master
|
||||
# TODO: remove --features master when it is back to the default.
|
||||
cargo test --features master
|
||||
./clean_all.sh
|
||||
|
||||
- name: Prepare dependencies
|
||||
|
|
@ -121,7 +123,8 @@ jobs:
|
|||
|
||||
- name: Run tests
|
||||
run: |
|
||||
./test.sh --release --clean --build-sysroot ${{ matrix.commands }}
|
||||
# TODO: remove --features master when it is back to the default.
|
||||
./test.sh --features master --release --clean --build-sysroot ${{ matrix.commands }}
|
||||
|
||||
duplicates:
|
||||
runs-on: ubuntu-latest
|
||||
|
|
|
|||
|
|
@ -21,11 +21,14 @@ jobs:
|
|||
libgccjit_version:
|
||||
- gcc: "libgccjit.so"
|
||||
artifacts_branch: "master"
|
||||
# TODO: switch back to --no-default-features in the case of libgccjit 12 when the default is to enable
|
||||
# master again.
|
||||
extra: "--features master"
|
||||
- gcc: "libgccjit_without_int128.so"
|
||||
artifacts_branch: "master-without-128bit-integers"
|
||||
extra: "--features master"
|
||||
- gcc: "libgccjit12.so"
|
||||
artifacts_branch: "gcc12"
|
||||
extra: "--no-default-features"
|
||||
# FIXME(antoyo): we need to set GCC_EXEC_PREFIX so that the linker can find the linker plugin.
|
||||
# Not sure why it's not found otherwise.
|
||||
env_extra: "TEST_FLAGS='-Cpanic=abort -Zpanic-abort-tests' GCC_EXEC_PREFIX=/usr/lib/gcc/"
|
||||
|
|
|
|||
|
|
@ -114,8 +114,10 @@ jobs:
|
|||
- name: Build
|
||||
run: |
|
||||
./y.sh prepare --only-libcore --cross
|
||||
./y.sh build --target-triple m68k-unknown-linux-gnu
|
||||
CG_GCC_TEST_TARGET=m68k-unknown-linux-gnu cargo test
|
||||
# TODO: remove --features master when it is back to the default.
|
||||
./y.sh build --target-triple m68k-unknown-linux-gnu --features master
|
||||
# TODO: remove --features master when it is back to the default.
|
||||
CG_GCC_TEST_TARGET=m68k-unknown-linux-gnu cargo test --features master
|
||||
./clean_all.sh
|
||||
|
||||
- name: Prepare dependencies
|
||||
|
|
@ -136,4 +138,5 @@ jobs:
|
|||
|
||||
- name: Run tests
|
||||
run: |
|
||||
./test.sh --release --clean --build-sysroot ${{ matrix.commands }}
|
||||
# TODO: remove --features master when it is back to the default.
|
||||
./test.sh --release --features master --clean --build-sysroot ${{ matrix.commands }}
|
||||
|
|
|
|||
|
|
@ -78,8 +78,10 @@ jobs:
|
|||
- name: Build
|
||||
run: |
|
||||
./y.sh prepare --only-libcore
|
||||
EMBED_LTO_BITCODE=1 ./y.sh build --release --release-sysroot
|
||||
cargo test
|
||||
# TODO: remove --features master when it is back to the default.
|
||||
EMBED_LTO_BITCODE=1 ./y.sh build --release --release-sysroot --features master
|
||||
# TODO: remove --features master when it is back to the default.
|
||||
cargo test --features master
|
||||
./clean_all.sh
|
||||
|
||||
- name: Prepare dependencies
|
||||
|
|
@ -102,4 +104,5 @@ jobs:
|
|||
|
||||
- name: Run tests
|
||||
run: |
|
||||
EMBED_LTO_BITCODE=1 ./test.sh --release --clean --release-sysroot --build-sysroot ${{ matrix.commands }}
|
||||
# TODO: remove --features master when it is back to the default.
|
||||
EMBED_LTO_BITCODE=1 ./test.sh --release --clean --release-sysroot --build-sysroot ${{ matrix.commands }} --features master
|
||||
|
|
|
|||
|
|
@ -92,8 +92,10 @@ jobs:
|
|||
- name: Build
|
||||
run: |
|
||||
./y.sh prepare --only-libcore
|
||||
./y.sh build --release --release-sysroot
|
||||
cargo test
|
||||
# TODO: remove `--features master` when it is back to the default.
|
||||
./y.sh build --release --release-sysroot --features master
|
||||
# TODO: remove --features master when it is back to the default.
|
||||
cargo test --features master
|
||||
|
||||
- name: Clean
|
||||
if: ${{ !matrix.cargo_runner }}
|
||||
|
|
@ -111,12 +113,14 @@ jobs:
|
|||
uses: actions-rs/cargo@v1.0.3
|
||||
with:
|
||||
command: build
|
||||
args: --release
|
||||
# TODO: remove `--features master` when it is back to the default.
|
||||
args: --release --features master
|
||||
|
||||
- name: Run tests
|
||||
if: ${{ !matrix.cargo_runner }}
|
||||
run: |
|
||||
./test.sh --release --clean --release-sysroot --build-sysroot --mini-tests --std-tests --test-libcore
|
||||
# TODO: remove `--features master` when it is back to the default.
|
||||
./test.sh --release --clean --release-sysroot --build-sysroot --mini-tests --std-tests --test-libcore --features master
|
||||
|
||||
- name: Run stdarch tests
|
||||
if: ${{ !matrix.cargo_runner }}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "gccjit"
|
||||
version = "1.0.0"
|
||||
source = "git+https://github.com/antoyo/gccjit.rs#c52a218f5529321285b4489e5562a00e5428e033"
|
||||
source = "git+https://github.com/antoyo/gccjit.rs#6e290f25b1d1edab5ae9ace486fd2dc8c08d6421"
|
||||
dependencies = [
|
||||
"gccjit_sys",
|
||||
]
|
||||
|
|
@ -82,7 +82,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "gccjit_sys"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/antoyo/gccjit.rs#c52a218f5529321285b4489e5562a00e5428e033"
|
||||
source = "git+https://github.com/antoyo/gccjit.rs#6e290f25b1d1edab5ae9ace486fd2dc8c08d6421"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -28,3 +28,7 @@ fi
|
|||
# Copy files to sysroot
|
||||
mkdir -p sysroot/lib/rustlib/$TARGET_TRIPLE/lib/
|
||||
cp -r target/$TARGET_TRIPLE/$sysroot_channel/deps/* sysroot/lib/rustlib/$TARGET_TRIPLE/lib/
|
||||
# Copy the source files to the sysroot (Rust for Linux needs this).
|
||||
source_dir=sysroot/lib/rustlib/src/rust
|
||||
mkdir -p $source_dir
|
||||
cp -r sysroot_src/library/ $source_dir
|
||||
|
|
|
|||
|
|
@ -194,6 +194,12 @@ fn build_sysroot(
|
|||
copier,
|
||||
)?;
|
||||
|
||||
// Copy the source files to the sysroot (Rust for Linux needs this).
|
||||
let sysroot_src_path = "sysroot/lib/rustlib/src/rust";
|
||||
fs::create_dir_all(&sysroot_src_path)
|
||||
.map_err(|error| format!("Failed to create directory `{}`: {:?}", sysroot_src_path, error))?;
|
||||
run_command(&[&"cp", &"-r", &"sysroot_src/library/", &sysroot_src_path], None)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,3 +38,5 @@ tests/ui/target-feature/missing-plusminus.rs
|
|||
tests/ui/sse2.rs
|
||||
tests/ui/codegen/issue-79865-llvm-miscompile.rs
|
||||
tests/ui/intrinsics/intrinsics-integer.rs
|
||||
tests/ui/std-backtrace.rs
|
||||
tests/ui/mir/alignment/packed.rs
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
From 7bcd24ec6d4a96121874cb1ae5a23ea274aeff34 Mon Sep 17 00:00:00 2001
|
||||
From a5663265f797a43c502915c356fe7899c16cee92 Mon Sep 17 00:00:00 2001
|
||||
From: None <none@example.com>
|
||||
Date: Thu, 19 Oct 2023 13:12:51 -0400
|
||||
Date: Sat, 18 Nov 2023 10:50:36 -0500
|
||||
Subject: [PATCH] [core] Disable portable-simd test
|
||||
|
||||
---
|
||||
|
|
@ -8,18 +8,18 @@ Subject: [PATCH] [core] Disable portable-simd test
|
|||
1 file changed, 2 deletions(-)
|
||||
|
||||
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
|
||||
index 5814ed4..194ad4c 100644
|
||||
index d0a119c..76fdece 100644
|
||||
--- a/library/core/tests/lib.rs
|
||||
+++ b/library/core/tests/lib.rs
|
||||
@@ -90,7 +90,6 @@
|
||||
@@ -89,7 +89,6 @@
|
||||
#![feature(never_type)]
|
||||
#![feature(unwrap_infallible)]
|
||||
#![feature(pointer_byte_offsets)]
|
||||
#![feature(pointer_is_aligned)]
|
||||
-#![feature(portable_simd)]
|
||||
#![feature(ptr_metadata)]
|
||||
#![feature(lazy_cell)]
|
||||
#![feature(unsized_tuple_coercion)]
|
||||
@@ -157,7 +156,6 @@ mod pin;
|
||||
@@ -155,7 +154,6 @@ mod pin;
|
||||
mod pin_macro;
|
||||
mod ptr;
|
||||
mod result;
|
||||
|
|
@ -28,5 +28,5 @@ index 5814ed4..194ad4c 100644
|
|||
mod str;
|
||||
mod str_lossy;
|
||||
--
|
||||
2.42.0
|
||||
2.42.1
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2023-10-21"
|
||||
channel = "nightly-2023-11-17"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ use std::env;
|
|||
use std::time::Instant;
|
||||
|
||||
use gccjit::{
|
||||
Context,
|
||||
FunctionType,
|
||||
GlobalKind,
|
||||
};
|
||||
|
|
@ -18,8 +17,9 @@ use rustc_codegen_ssa::mono_item::MonoItemExt;
|
|||
use rustc_codegen_ssa::traits::DebugInfoMethods;
|
||||
use rustc_session::config::DebugInfo;
|
||||
use rustc_span::Symbol;
|
||||
use rustc_target::spec::PanicStrategy;
|
||||
|
||||
use crate::{LockedTargetInfo, gcc_util};
|
||||
use crate::{LockedTargetInfo, gcc_util, new_context};
|
||||
use crate::GccContext;
|
||||
use crate::builder::Builder;
|
||||
use crate::context::CodegenCx;
|
||||
|
|
@ -88,20 +88,18 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: Lock
|
|||
fn module_codegen(tcx: TyCtxt<'_>, (cgu_name, target_info): (Symbol, LockedTargetInfo)) -> ModuleCodegen<GccContext> {
|
||||
let cgu = tcx.codegen_unit(cgu_name);
|
||||
// Instantiate monomorphizations without filling out definitions yet...
|
||||
let context = Context::default();
|
||||
let context = new_context(tcx);
|
||||
|
||||
context.add_command_line_option("-fexceptions");
|
||||
context.add_driver_option("-fexceptions");
|
||||
if tcx.sess.panic_strategy() == PanicStrategy::Unwind {
|
||||
context.add_command_line_option("-fexceptions");
|
||||
context.add_driver_option("-fexceptions");
|
||||
}
|
||||
|
||||
let disabled_features: HashSet<_> = tcx.sess.opts.cg.target_feature.split(',')
|
||||
.filter(|feature| feature.starts_with('-'))
|
||||
.map(|string| &string[1..])
|
||||
.collect();
|
||||
|
||||
if tcx.sess.target.arch == "x86" || tcx.sess.target.arch == "x86_64" {
|
||||
context.add_command_line_option("-masm=intel");
|
||||
}
|
||||
|
||||
if !disabled_features.contains("avx") && tcx.sess.target.arch == "x86_64" {
|
||||
// NOTE: we always enable AVX because the equivalent of llvm.x86.sse2.cmp.pd in GCC for
|
||||
// SSE2 is multiple builtins, so we use the AVX __builtin_ia32_cmppd instead.
|
||||
|
|
|
|||
|
|
@ -76,6 +76,9 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
a >> b
|
||||
}
|
||||
}
|
||||
else if a_type.is_vector() && a_type.is_vector() {
|
||||
a >> b
|
||||
}
|
||||
else if a_native && !b_native {
|
||||
self.gcc_lshr(a, self.gcc_int_cast(b, a_type))
|
||||
}
|
||||
|
|
@ -144,7 +147,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
fn additive_operation(&self, operation: BinaryOp, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
let a_type = a.get_type();
|
||||
let b_type = b.get_type();
|
||||
if self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type) {
|
||||
if (self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type)) || (a_type.is_vector() && b_type.is_vector()) {
|
||||
if a_type != b_type {
|
||||
if a_type.is_vector() {
|
||||
// Vector types need to be bitcast.
|
||||
|
|
@ -158,6 +161,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
self.context.new_binary_op(None, operation, a_type, a, b)
|
||||
}
|
||||
else {
|
||||
debug_assert!(a_type.dyncast_array().is_some());
|
||||
debug_assert!(b_type.dyncast_array().is_some());
|
||||
let signed = a_type.is_compatible_with(self.i128_type);
|
||||
let func_name =
|
||||
match (operation, signed) {
|
||||
|
|
@ -189,10 +194,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
fn multiplicative_operation(&self, operation: BinaryOp, operation_name: &str, signed: bool, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
let a_type = a.get_type();
|
||||
let b_type = b.get_type();
|
||||
if self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type) {
|
||||
if (self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type)) || (a_type.is_vector() && b_type.is_vector()) {
|
||||
self.context.new_binary_op(None, operation, a_type, a, b)
|
||||
}
|
||||
else {
|
||||
debug_assert!(a_type.dyncast_array().is_some());
|
||||
debug_assert!(b_type.dyncast_array().is_some());
|
||||
let sign =
|
||||
if signed {
|
||||
""
|
||||
|
|
@ -337,6 +344,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
pub fn operation_with_overflow(&self, func_name: &str, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) {
|
||||
let a_type = lhs.get_type();
|
||||
let b_type = rhs.get_type();
|
||||
debug_assert!(a_type.dyncast_array().is_some());
|
||||
debug_assert!(b_type.dyncast_array().is_some());
|
||||
let param_a = self.context.new_parameter(None, a_type, "a");
|
||||
let param_b = self.context.new_parameter(None, b_type, "b");
|
||||
let result_field = self.context.new_field(None, a_type, "result");
|
||||
|
|
@ -496,7 +505,11 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
pub fn gcc_xor(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
|
||||
let a_type = a.get_type();
|
||||
let b_type = b.get_type();
|
||||
if self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type) {
|
||||
if a_type.is_vector() && b_type.is_vector() {
|
||||
let b = self.bitcast_if_needed(b, a_type);
|
||||
a ^ b
|
||||
}
|
||||
else if self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type) {
|
||||
a ^ b
|
||||
}
|
||||
else {
|
||||
|
|
@ -527,6 +540,9 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
a << b
|
||||
}
|
||||
}
|
||||
else if a_type.is_vector() && a_type.is_vector() {
|
||||
a << b
|
||||
}
|
||||
else if a_native && !b_native {
|
||||
self.gcc_shl(a, self.gcc_int_cast(b, a_type))
|
||||
}
|
||||
|
|
@ -690,6 +706,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
let a_native = self.is_native_int_type_or_bool(a_type);
|
||||
let b_native = self.is_native_int_type_or_bool(b_type);
|
||||
if a_type.is_vector() && b_type.is_vector() {
|
||||
let b = self.bitcast_if_needed(b, a_type);
|
||||
self.context.new_binary_op(None, operation, a_type, a, b)
|
||||
}
|
||||
else if a_native && b_native {
|
||||
|
|
@ -748,6 +765,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
return self.context.new_cast(None, value, dest_typ);
|
||||
}
|
||||
|
||||
debug_assert!(value_type.dyncast_array().is_some());
|
||||
let name_suffix =
|
||||
match self.type_kind(dest_typ) {
|
||||
TypeKind::Float => "tisf",
|
||||
|
|
@ -781,6 +799,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
return self.context.new_cast(None, value, dest_typ);
|
||||
}
|
||||
|
||||
debug_assert!(value_type.dyncast_array().is_some());
|
||||
let name_suffix =
|
||||
match self.type_kind(value_type) {
|
||||
TypeKind::Float => "sfti",
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ extern crate rustc_errors;
|
|||
extern crate rustc_fluent_macro;
|
||||
extern crate rustc_fs_util;
|
||||
extern crate rustc_hir;
|
||||
#[cfg(feature="master")]
|
||||
extern crate rustc_interface;
|
||||
extern crate rustc_macros;
|
||||
extern crate rustc_metadata;
|
||||
extern crate rustc_middle;
|
||||
|
|
@ -86,7 +88,7 @@ use std::sync::atomic::Ordering;
|
|||
|
||||
use gccjit::{Context, OptimizationLevel};
|
||||
#[cfg(feature="master")]
|
||||
use gccjit::TargetInfo;
|
||||
use gccjit::{TargetInfo, Version};
|
||||
#[cfg(not(feature="master"))]
|
||||
use gccjit::CType;
|
||||
use errors::LTONotSupported;
|
||||
|
|
@ -244,17 +246,33 @@ impl CodegenBackend for GccCodegenBackend {
|
|||
}
|
||||
}
|
||||
|
||||
fn new_context<'gcc, 'tcx>(tcx: TyCtxt<'tcx>) -> Context<'gcc> {
|
||||
let context = Context::default();
|
||||
if tcx.sess.target.arch == "x86" || tcx.sess.target.arch == "x86_64" {
|
||||
context.add_command_line_option("-masm=intel");
|
||||
}
|
||||
#[cfg(feature="master")]
|
||||
{
|
||||
let version = Version::get();
|
||||
let version = format!("{}.{}.{}", version.major, version.minor, version.patch);
|
||||
context.set_output_ident(&format!("rustc version {} with libgccjit {}",
|
||||
rustc_interface::util::rustc_version_str().unwrap_or("unknown version"),
|
||||
version,
|
||||
));
|
||||
}
|
||||
// TODO(antoyo): check if this should only be added when using -Cforce-unwind-tables=n.
|
||||
context.add_command_line_option("-fno-asynchronous-unwind-tables");
|
||||
context
|
||||
}
|
||||
|
||||
impl ExtraBackendMethods for GccCodegenBackend {
|
||||
fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) -> Self::Module {
|
||||
let mut mods = GccContext {
|
||||
context: Context::default(),
|
||||
context: new_context(tcx),
|
||||
should_combine_object_files: false,
|
||||
temp_dir: None,
|
||||
};
|
||||
|
||||
if tcx.sess.target.arch == "x86" || tcx.sess.target.arch == "x86_64" {
|
||||
mods.context.add_command_line_option("-masm=intel");
|
||||
}
|
||||
unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, alloc_error_handler_kind); }
|
||||
mods
|
||||
}
|
||||
|
|
|
|||
|
|
@ -348,50 +348,18 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||
PassMode::Direct(_) => {
|
||||
// ABI-compatible Rust types have the same `layout.abi` (up to validity ranges),
|
||||
// and for Scalar ABIs the LLVM type is fully determined by `layout.abi`,
|
||||
// guarnateeing that we generate ABI-compatible LLVM IR. Things get tricky for
|
||||
// aggregates...
|
||||
if matches!(arg.layout.abi, abi::Abi::Aggregate { .. }) {
|
||||
assert!(
|
||||
arg.layout.is_sized(),
|
||||
"`PassMode::Direct` for unsized type: {}",
|
||||
arg.layout.ty
|
||||
);
|
||||
// This really shouldn't happen, since `immediate_llvm_type` will use
|
||||
// `layout.fields` to turn this Rust type into an LLVM type. This means all
|
||||
// sorts of Rust type details leak into the ABI. However wasm sadly *does*
|
||||
// currently use this mode so we have to allow it -- but we absolutely
|
||||
// shouldn't let any more targets do that.
|
||||
// (Also see <https://github.com/rust-lang/rust/issues/115666>.)
|
||||
//
|
||||
// The unstable abi `PtxKernel` also uses Direct for now.
|
||||
// It needs to switch to something else before stabilization can happen.
|
||||
// (See issue: https://github.com/rust-lang/rust/issues/117271)
|
||||
assert!(
|
||||
matches!(&*cx.tcx.sess.target.arch, "wasm32" | "wasm64")
|
||||
|| self.conv == Conv::PtxKernel,
|
||||
"`PassMode::Direct` for aggregates only allowed on wasm and `extern \"ptx-kernel\"` fns\nProblematic type: {:#?}",
|
||||
arg.layout,
|
||||
);
|
||||
}
|
||||
// guaranteeing that we generate ABI-compatible LLVM IR.
|
||||
arg.layout.immediate_llvm_type(cx)
|
||||
}
|
||||
PassMode::Pair(..) => {
|
||||
// ABI-compatible Rust types have the same `layout.abi` (up to validity ranges),
|
||||
// so for ScalarPair we can easily be sure that we are generating ABI-compatible
|
||||
// LLVM IR.
|
||||
assert!(
|
||||
matches!(arg.layout.abi, abi::Abi::ScalarPair(..)),
|
||||
"PassMode::Pair for type {}",
|
||||
arg.layout.ty
|
||||
);
|
||||
llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0, true));
|
||||
llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true));
|
||||
continue;
|
||||
}
|
||||
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack } => {
|
||||
// `Indirect` with metadata is only for unsized types, and doesn't work with
|
||||
// on-stack passing.
|
||||
assert!(arg.layout.is_unsized() && !on_stack);
|
||||
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
|
||||
// Construct the type of a (wide) pointer to `ty`, and pass its two fields.
|
||||
// Any two ABI-compatible unsized types have the same metadata type and
|
||||
// moreover the same metadata value leads to the same dynamic size and
|
||||
|
|
@ -402,13 +370,8 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||
llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 1, true));
|
||||
continue;
|
||||
}
|
||||
PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
|
||||
assert!(arg.layout.is_sized());
|
||||
cx.type_ptr()
|
||||
}
|
||||
PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => cx.type_ptr(),
|
||||
PassMode::Cast { cast, pad_i32 } => {
|
||||
// `Cast` means "transmute to `CastType`"; that only makes sense for sized types.
|
||||
assert!(arg.layout.is_sized());
|
||||
// add padding
|
||||
if *pad_i32 {
|
||||
llargument_tys.push(Reg::i32().llvm_type(cx));
|
||||
|
|
|
|||
|
|
@ -990,11 +990,7 @@ unsafe fn embed_bitcode(
|
|||
// reason (see issue #90326 for historical background).
|
||||
let is_aix = target_is_aix(cgcx);
|
||||
let is_apple = target_is_apple(cgcx);
|
||||
if is_apple
|
||||
|| is_aix
|
||||
|| cgcx.opts.target_triple.triple().starts_with("wasm")
|
||||
|| cgcx.opts.target_triple.triple().starts_with("asmjs")
|
||||
{
|
||||
if is_apple || is_aix || cgcx.opts.target_triple.triple().starts_with("wasm") {
|
||||
// We don't need custom section flags, create LLVM globals.
|
||||
let llconst = common::bytes_in_context(llcx, bitcode);
|
||||
let llglobal = llvm::LLVMAddGlobal(
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ libc = "0.2.50"
|
|||
# tidy-alphabetical-end
|
||||
|
||||
[dependencies.object]
|
||||
version = "0.32.0"
|
||||
version = "0.32.1"
|
||||
default-features = false
|
||||
features = ["read_core", "elf", "macho", "pe", "xcoff", "unaligned", "archive", "write"]
|
||||
|
||||
|
|
|
|||
|
|
@ -2243,9 +2243,9 @@ fn linker_with_args<'a>(
|
|||
// ------------ Late order-dependent options ------------
|
||||
|
||||
// Doesn't really make sense.
|
||||
// FIXME: In practice built-in target specs use this for arbitrary order-independent options,
|
||||
// introduce a target spec option for order-independent linker options, migrate built-in specs
|
||||
// to it and remove the option.
|
||||
// FIXME: In practice built-in target specs use this for arbitrary order-independent options.
|
||||
// Introduce a target spec option for order-independent linker options, migrate built-in specs
|
||||
// to it and remove the option. Currently the last holdout is wasm32-unknown-emscripten.
|
||||
add_post_link_args(cmd, sess, flavor);
|
||||
|
||||
Ok(cmd.take_cmd())
|
||||
|
|
|
|||
|
|
@ -226,6 +226,10 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
|
|||
|
||||
let mut file = write::Object::new(binary_format, architecture, endianness);
|
||||
if sess.target.is_like_osx {
|
||||
if macho_is_arm64e(&sess.target) {
|
||||
file.set_macho_cpu_subtype(object::macho::CPU_SUBTYPE_ARM64E);
|
||||
}
|
||||
|
||||
file.set_macho_build_version(macho_object_build_version_for_target(&sess.target))
|
||||
}
|
||||
if binary_format == BinaryFormat::Coff {
|
||||
|
|
@ -385,6 +389,11 @@ fn macho_object_build_version_for_target(target: &Target) -> object::write::Mach
|
|||
build_version
|
||||
}
|
||||
|
||||
/// Is Apple's CPU subtype `arm64e`s
|
||||
fn macho_is_arm64e(target: &Target) -> bool {
|
||||
return target.llvm_target.starts_with("arm64e");
|
||||
}
|
||||
|
||||
pub enum MetadataPosition {
|
||||
First,
|
||||
Last,
|
||||
|
|
|
|||
|
|
@ -322,8 +322,13 @@ pub fn cast_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
if lhs_sz < rhs_sz {
|
||||
bx.trunc(rhs, lhs_llty)
|
||||
} else if lhs_sz > rhs_sz {
|
||||
// FIXME (#1877: If in the future shifting by negative
|
||||
// values is no longer undefined then this is wrong.
|
||||
// We zero-extend even if the RHS is signed. So e.g. `(x: i32) << -1i8` will zero-extend the
|
||||
// RHS to `255i32`. But then we mask the shift amount to be within the size of the LHS
|
||||
// anyway so the result is `31` as it should be. All the extra bits introduced by zext
|
||||
// are masked off so their value does not matter.
|
||||
// FIXME: if we ever support 512bit integers, this will be wrong! For such large integers,
|
||||
// the extra bits introduced by zext are *not* all masked away any more.
|
||||
assert!(lhs_sz <= 256);
|
||||
bx.zext(rhs, lhs_llty)
|
||||
} else {
|
||||
rhs
|
||||
|
|
|
|||
|
|
@ -249,7 +249,7 @@ fn push_debuginfo_type_name<'tcx>(
|
|||
.projection_bounds()
|
||||
.map(|bound| {
|
||||
let ExistentialProjection { def_id: item_def_id, term, .. } =
|
||||
tcx.erase_late_bound_regions(bound);
|
||||
tcx.instantiate_bound_regions_with_erased(bound);
|
||||
// FIXME(associated_const_equality): allow for consts here
|
||||
(item_def_id, term.ty().unwrap())
|
||||
})
|
||||
|
|
|
|||
|
|
@ -107,6 +107,14 @@ impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxIndexMap<K, V> {
|
|||
FxIndexMap::contains_key(self, k)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn contains_key_ref<Q: ?Sized + Hash + Eq>(&self, k: &Q) -> bool
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
{
|
||||
FxIndexMap::contains_key(self, k)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn insert(&mut self, k: K, v: V) -> Option<V> {
|
||||
FxIndexMap::insert(self, k, v)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use rustc_middle::mir;
|
|||
use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_target::abi::VariantIdx;
|
||||
use rustc_target::abi::{Abi, VariantIdx};
|
||||
|
||||
#[instrument(skip(ecx), level = "debug")]
|
||||
fn branches<'tcx>(
|
||||
|
|
@ -101,11 +101,16 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
|
|||
// Not all raw pointers are allowed, as we cannot properly test them for
|
||||
// equality at compile-time (see `ptr_guaranteed_cmp`).
|
||||
// However we allow those that are just integers in disguise.
|
||||
// (We could allow wide raw pointers where both sides are integers in the future,
|
||||
// but for now we reject them.)
|
||||
let Ok(val) = ecx.read_scalar(place) else {
|
||||
// First, get the pointer. Remember it might be wide!
|
||||
let Ok(val) = ecx.read_immediate(place) else {
|
||||
return Err(ValTreeCreationError::Other);
|
||||
};
|
||||
// We could allow wide raw pointers where both sides are integers in the future,
|
||||
// but for now we reject them.
|
||||
if matches!(val.layout.abi, Abi::ScalarPair(..)) {
|
||||
return Err(ValTreeCreationError::Other);
|
||||
}
|
||||
let val = val.to_scalar();
|
||||
// We are in the CTFE machine, so ptr-to-int casts will fail.
|
||||
// This can only be `Ok` if `val` already is an integer.
|
||||
let Ok(val) = val.try_to_int() else {
|
||||
|
|
|
|||
|
|
@ -49,6 +49,14 @@ pub trait AllocMap<K: Hash + Eq, V> {
|
|||
where
|
||||
K: Borrow<Q>;
|
||||
|
||||
/// Callers should prefer [`AllocMap::contains_key`] when it is possible to call because it may
|
||||
/// be more efficient. This function exists for callers that only have a shared reference
|
||||
/// (which might make it slightly less efficient than `contains_key`, e.g. if
|
||||
/// the data is stored inside a `RefCell`).
|
||||
fn contains_key_ref<Q: ?Sized + Hash + Eq>(&self, k: &Q) -> bool
|
||||
where
|
||||
K: Borrow<Q>;
|
||||
|
||||
/// Inserts a new entry into the map.
|
||||
fn insert(&mut self, k: K, v: V) -> Option<V>;
|
||||
|
||||
|
|
|
|||
|
|
@ -692,6 +692,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
Ok((&mut alloc.extra, machine))
|
||||
}
|
||||
|
||||
/// Check whether an allocation is live. This is faster than calling
|
||||
/// [`InterpCx::get_alloc_info`] if all you need to check is whether the kind is
|
||||
/// [`AllocKind::Dead`] because it doesn't have to look up the type and layout of statics.
|
||||
pub fn is_alloc_live(&self, id: AllocId) -> bool {
|
||||
self.tcx.try_get_global_alloc(id).is_some()
|
||||
|| self.memory.alloc_map.contains_key_ref(&id)
|
||||
|| self.memory.extra_fn_ptr_map.contains_key(&id)
|
||||
}
|
||||
|
||||
/// Obtain the size and alignment of an allocation, even if that allocation has
|
||||
/// been deallocated.
|
||||
pub fn get_alloc_info(&self, id: AllocId) -> (Size, Align, AllocKind) {
|
||||
|
|
|
|||
|
|
@ -156,41 +156,35 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
|
||||
// Shift ops can have an RHS with a different numeric type.
|
||||
if matches!(bin_op, Shl | ShlUnchecked | Shr | ShrUnchecked) {
|
||||
let size = u128::from(left_layout.size.bits());
|
||||
// Even if `r` is signed, we treat it as if it was unsigned (i.e., we use its
|
||||
// zero-extended form). This matches the codegen backend:
|
||||
// <https://github.com/rust-lang/rust/blob/c274e4969f058b1c644243181ece9f829efa7594/compiler/rustc_codegen_ssa/src/base.rs#L315-L317>.
|
||||
// The overflow check is also ignorant to the sign:
|
||||
// <https://github.com/rust-lang/rust/blob/c274e4969f058b1c644243181ece9f829efa7594/compiler/rustc_codegen_ssa/src/mir/rvalue.rs#L728>.
|
||||
// This would behave rather strangely if we had integer types of size 256: a shift by
|
||||
// -1i8 would actually shift by 255, but that would *not* be considered overflowing. A
|
||||
// shift by -1i16 though would be considered overflowing. If we had integers of size
|
||||
// 512, then a shift by -1i8 would even produce a different result than one by -1i16:
|
||||
// the first shifts by 255, the latter by u16::MAX % 512 = 511. Lucky enough, our
|
||||
// integers are maximally 128bits wide, so negative shifts *always* overflow and we have
|
||||
// consistent results for the same value represented at different bit widths.
|
||||
assert!(size <= 128);
|
||||
let original_r = r;
|
||||
let overflow = r >= size;
|
||||
// The shift offset is implicitly masked to the type size, to make sure this operation
|
||||
// is always defined. This is the one MIR operator that does *not* directly map to a
|
||||
// single LLVM operation. See
|
||||
// <https://github.com/rust-lang/rust/blob/c274e4969f058b1c644243181ece9f829efa7594/compiler/rustc_codegen_ssa/src/common.rs#L131-L158>
|
||||
// for the corresponding truncation in our codegen backends.
|
||||
let r = r % size;
|
||||
let r = u32::try_from(r).unwrap(); // we masked so this will always fit
|
||||
let size = left_layout.size.bits();
|
||||
// The shift offset is implicitly masked to the type size. (This is the one MIR operator
|
||||
// that does *not* directly map to a single LLVM operation.) Compute how much we
|
||||
// actually shift and whether there was an overflow due to shifting too much.
|
||||
let (shift_amount, overflow) = if right_layout.abi.is_signed() {
|
||||
let shift_amount = self.sign_extend(r, right_layout) as i128;
|
||||
let overflow = shift_amount < 0 || shift_amount >= i128::from(size);
|
||||
let masked_amount = (shift_amount as u128) % u128::from(size);
|
||||
debug_assert_eq!(overflow, shift_amount != (masked_amount as i128));
|
||||
(masked_amount, overflow)
|
||||
} else {
|
||||
let shift_amount = r;
|
||||
let masked_amount = shift_amount % u128::from(size);
|
||||
(masked_amount, shift_amount != masked_amount)
|
||||
};
|
||||
let shift_amount = u32::try_from(shift_amount).unwrap(); // we masked so this will always fit
|
||||
// Compute the shifted result.
|
||||
let result = if left_layout.abi.is_signed() {
|
||||
let l = self.sign_extend(l, left_layout) as i128;
|
||||
let result = match bin_op {
|
||||
Shl | ShlUnchecked => l.checked_shl(r).unwrap(),
|
||||
Shr | ShrUnchecked => l.checked_shr(r).unwrap(),
|
||||
Shl | ShlUnchecked => l.checked_shl(shift_amount).unwrap(),
|
||||
Shr | ShrUnchecked => l.checked_shr(shift_amount).unwrap(),
|
||||
_ => bug!(),
|
||||
};
|
||||
result as u128
|
||||
} else {
|
||||
match bin_op {
|
||||
Shl | ShlUnchecked => l.checked_shl(r).unwrap(),
|
||||
Shr | ShrUnchecked => l.checked_shr(r).unwrap(),
|
||||
Shl | ShlUnchecked => l.checked_shl(shift_amount).unwrap(),
|
||||
Shr | ShrUnchecked => l.checked_shr(shift_amount).unwrap(),
|
||||
_ => bug!(),
|
||||
}
|
||||
};
|
||||
|
|
@ -199,7 +193,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
if overflow && let Some(intrinsic_name) = throw_ub_on_overflow {
|
||||
throw_ub_custom!(
|
||||
fluent::const_eval_overflow_shift,
|
||||
val = original_r,
|
||||
val = if right_layout.abi.is_signed() {
|
||||
(self.sign_extend(r, right_layout) as i128).to_string()
|
||||
} else {
|
||||
r.to_string()
|
||||
},
|
||||
name = intrinsic_name
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -864,6 +864,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
};
|
||||
|
||||
// Use the underlying local for this (necessarily interior) borrow.
|
||||
debug_assert!(region.is_erased());
|
||||
let ty = local_decls[place.local].ty;
|
||||
let span = statement.source_info.span;
|
||||
|
||||
|
|
@ -873,8 +874,6 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||
ty::TypeAndMut { ty, mutbl: borrow_kind.to_mutbl_lossy() },
|
||||
);
|
||||
|
||||
*region = tcx.lifetimes.re_erased;
|
||||
|
||||
let mut projection = vec![PlaceElem::Deref];
|
||||
projection.extend(place.projection);
|
||||
place.projection = tcx.mk_place_elems(&projection);
|
||||
|
|
|
|||
|
|
@ -285,6 +285,12 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> {
|
|||
UnwindAction::Unreachable | UnwindAction::Terminate(UnwindTerminateReason::Abi) => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_critical_call_edge(&self, target: Option<BasicBlock>, unwind: UnwindAction) -> bool {
|
||||
let Some(target) = target else { return false };
|
||||
matches!(unwind, UnwindAction::Cleanup(_) | UnwindAction::Terminate(_))
|
||||
&& self.body.basic_blocks.predecessors()[target].len() > 1
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
|
||||
|
|
@ -425,6 +431,22 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
|
|||
}
|
||||
self.check_unwind_edge(location, *unwind);
|
||||
|
||||
// The code generation assumes that there are no critical call edges. The assumption
|
||||
// is used to simplify inserting code that should be executed along the return edge
|
||||
// from the call. FIXME(tmiasko): Since this is a strictly code generation concern,
|
||||
// the code generation should be responsible for handling it.
|
||||
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Optimized)
|
||||
&& self.is_critical_call_edge(*target, *unwind)
|
||||
{
|
||||
self.fail(
|
||||
location,
|
||||
format!(
|
||||
"encountered critical edge in `Call` terminator {:?}",
|
||||
terminator.kind,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// The call destination place and Operand::Move place used as an argument might be
|
||||
// passed by a reference to the callee. Consequently they must be non-overlapping
|
||||
// and cannot be packed. Currently this simply checks for duplicate places.
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ rustc_privacy = { path = "../rustc_privacy" }
|
|||
rustc_query_system = { path = "../rustc_query_system" }
|
||||
rustc_resolve = { path = "../rustc_resolve" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_smir ={ path = "../rustc_smir" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ use rustc_feature::find_gated_cfg;
|
|||
use rustc_fluent_macro::fluent_messages;
|
||||
use rustc_interface::util::{self, collect_crate_types, get_codegen_backend};
|
||||
use rustc_interface::{interface, Queries};
|
||||
use rustc_lint::{unerased_lint_store, LintStore};
|
||||
use rustc_lint::unerased_lint_store;
|
||||
use rustc_metadata::locator;
|
||||
use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS};
|
||||
use rustc_session::config::{ErrorOutputType, Input, OutFileName, OutputType, TrimmedDefPaths};
|
||||
|
|
@ -293,7 +293,7 @@ fn run_compiler(
|
|||
>,
|
||||
using_internal_features: Arc<std::sync::atomic::AtomicBool>,
|
||||
) -> interface::Result<()> {
|
||||
let mut early_error_handler = EarlyErrorHandler::new(ErrorOutputType::default());
|
||||
let mut default_handler = EarlyErrorHandler::new(ErrorOutputType::default());
|
||||
|
||||
// Throw away the first argument, the name of the binary.
|
||||
// In case of at_args being empty, as might be the case by
|
||||
|
|
@ -305,14 +305,14 @@ fn run_compiler(
|
|||
// the compiler with @empty_file as argv[0] and no more arguments.
|
||||
let at_args = at_args.get(1..).unwrap_or_default();
|
||||
|
||||
let args = args::arg_expand_all(&early_error_handler, at_args);
|
||||
let args = args::arg_expand_all(&default_handler, at_args);
|
||||
|
||||
let Some(matches) = handle_options(&early_error_handler, &args) else { return Ok(()) };
|
||||
let Some(matches) = handle_options(&default_handler, &args) else { return Ok(()) };
|
||||
|
||||
let sopts = config::build_session_options(&mut early_error_handler, &matches);
|
||||
let sopts = config::build_session_options(&mut default_handler, &matches);
|
||||
|
||||
if let Some(ref code) = matches.opt_str("explain") {
|
||||
handle_explain(&early_error_handler, diagnostics_registry(), code, sopts.color);
|
||||
handle_explain(&default_handler, diagnostics_registry(), code, sopts.color);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
|
@ -338,71 +338,56 @@ fn run_compiler(
|
|||
expanded_args: args,
|
||||
};
|
||||
|
||||
match make_input(&early_error_handler, &matches.free) {
|
||||
let has_input = match make_input(&default_handler, &matches.free) {
|
||||
Err(reported) => return Err(reported),
|
||||
Ok(Some(input)) => {
|
||||
config.input = input;
|
||||
|
||||
callbacks.config(&mut config);
|
||||
true // has input: normal compilation
|
||||
}
|
||||
Ok(None) => match matches.free.len() {
|
||||
0 => {
|
||||
callbacks.config(&mut config);
|
||||
|
||||
early_error_handler.abort_if_errors();
|
||||
|
||||
interface::run_compiler(config, |compiler| {
|
||||
let sopts = &compiler.session().opts;
|
||||
let handler = EarlyErrorHandler::new(sopts.error_format);
|
||||
|
||||
if sopts.describe_lints {
|
||||
let mut lint_store =
|
||||
rustc_lint::new_lint_store(compiler.session().enable_internal_lints());
|
||||
let registered_lints =
|
||||
if let Some(register_lints) = compiler.register_lints() {
|
||||
register_lints(compiler.session(), &mut lint_store);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
describe_lints(compiler.session(), &lint_store, registered_lints);
|
||||
return;
|
||||
}
|
||||
let should_stop = print_crate_info(
|
||||
&handler,
|
||||
&**compiler.codegen_backend(),
|
||||
compiler.session(),
|
||||
false,
|
||||
);
|
||||
|
||||
if should_stop == Compilation::Stop {
|
||||
return;
|
||||
}
|
||||
handler.early_error("no input filename given")
|
||||
});
|
||||
return Ok(());
|
||||
}
|
||||
0 => false, // no input: we will exit early
|
||||
1 => panic!("make_input should have provided valid inputs"),
|
||||
_ => early_error_handler.early_error(format!(
|
||||
_ => default_handler.early_error(format!(
|
||||
"multiple input filenames provided (first two filenames are `{}` and `{}`)",
|
||||
matches.free[0], matches.free[1],
|
||||
)),
|
||||
},
|
||||
};
|
||||
|
||||
early_error_handler.abort_if_errors();
|
||||
callbacks.config(&mut config);
|
||||
|
||||
default_handler.abort_if_errors();
|
||||
drop(default_handler);
|
||||
|
||||
interface::run_compiler(config, |compiler| {
|
||||
let sess = compiler.session();
|
||||
let codegen_backend = compiler.codegen_backend();
|
||||
|
||||
// This implements `-Whelp`. It should be handled very early, like
|
||||
// `--help`/`-Zhelp`/`-Chelp`. This is the earliest it can run, because
|
||||
// it must happen after lints are registered, during session creation.
|
||||
if sess.opts.describe_lints {
|
||||
describe_lints(sess);
|
||||
return sess.compile_status();
|
||||
}
|
||||
|
||||
let handler = EarlyErrorHandler::new(sess.opts.error_format);
|
||||
|
||||
let should_stop = print_crate_info(&handler, &**compiler.codegen_backend(), sess, true)
|
||||
.and_then(|| {
|
||||
list_metadata(&handler, sess, &*compiler.codegen_backend().metadata_loader())
|
||||
})
|
||||
.and_then(|| try_process_rlink(sess, compiler));
|
||||
if print_crate_info(&handler, codegen_backend, sess, has_input) == Compilation::Stop {
|
||||
return sess.compile_status();
|
||||
}
|
||||
|
||||
if should_stop == Compilation::Stop {
|
||||
if !has_input {
|
||||
handler.early_error("no input filename given"); // this is fatal
|
||||
}
|
||||
|
||||
if !sess.opts.unstable_opts.ls.is_empty() {
|
||||
list_metadata(&handler, sess, &*codegen_backend.metadata_loader());
|
||||
return sess.compile_status();
|
||||
}
|
||||
|
||||
if sess.opts.unstable_opts.link_only {
|
||||
process_rlink(sess, compiler);
|
||||
return sess.compile_status();
|
||||
}
|
||||
|
||||
|
|
@ -441,13 +426,6 @@ fn run_compiler(
|
|||
return early_exit();
|
||||
}
|
||||
|
||||
if sess.opts.describe_lints {
|
||||
queries
|
||||
.global_ctxt()?
|
||||
.enter(|tcx| describe_lints(sess, unerased_lint_store(tcx), true));
|
||||
return early_exit();
|
||||
}
|
||||
|
||||
// Make sure name resolution and macro expansion is run.
|
||||
queries.global_ctxt()?.enter(|tcx| tcx.resolver_for_lowering(()));
|
||||
|
||||
|
|
@ -493,7 +471,7 @@ fn run_compiler(
|
|||
|
||||
if let Some(linker) = linker {
|
||||
let _timer = sess.timer("link");
|
||||
linker.link()?
|
||||
linker.link(sess, codegen_backend)?
|
||||
}
|
||||
|
||||
if sess.opts.unstable_opts.print_fuel.is_some() {
|
||||
|
|
@ -562,15 +540,6 @@ pub enum Compilation {
|
|||
Continue,
|
||||
}
|
||||
|
||||
impl Compilation {
|
||||
fn and_then<F: FnOnce() -> Compilation>(self, next: F) -> Compilation {
|
||||
match self {
|
||||
Compilation::Stop => Compilation::Stop,
|
||||
Compilation::Continue => next(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_explain(handler: &EarlyErrorHandler, registry: Registry, code: &str, color: ColorConfig) {
|
||||
let upper_cased_code = code.to_ascii_uppercase();
|
||||
let normalised =
|
||||
|
|
@ -675,44 +644,34 @@ fn show_md_content_with_pager(content: &str, color: ColorConfig) {
|
|||
}
|
||||
}
|
||||
|
||||
fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Compilation {
|
||||
if sess.opts.unstable_opts.link_only {
|
||||
if let Input::File(file) = &sess.io.input {
|
||||
let outputs = compiler.build_output_filenames(sess, &[]);
|
||||
let rlink_data = fs::read(file).unwrap_or_else(|err| {
|
||||
sess.emit_fatal(RlinkUnableToRead { err });
|
||||
});
|
||||
let codegen_results = match CodegenResults::deserialize_rlink(sess, rlink_data) {
|
||||
Ok(codegen) => codegen,
|
||||
Err(err) => {
|
||||
match err {
|
||||
CodegenErrors::WrongFileType => sess.emit_fatal(RLinkWrongFileType),
|
||||
CodegenErrors::EmptyVersionNumber => {
|
||||
sess.emit_fatal(RLinkEmptyVersionNumber)
|
||||
}
|
||||
CodegenErrors::EncodingVersionMismatch { version_array, rlink_version } => {
|
||||
sess.emit_fatal(RLinkEncodingVersionMismatch {
|
||||
version_array,
|
||||
rlink_version,
|
||||
})
|
||||
}
|
||||
CodegenErrors::RustcVersionMismatch { rustc_version } => {
|
||||
sess.emit_fatal(RLinkRustcVersionMismatch {
|
||||
rustc_version,
|
||||
current_version: sess.cfg_version,
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
let result = compiler.codegen_backend().link(sess, codegen_results, &outputs);
|
||||
abort_on_err(result, sess);
|
||||
} else {
|
||||
sess.emit_fatal(RlinkNotAFile {})
|
||||
}
|
||||
Compilation::Stop
|
||||
fn process_rlink(sess: &Session, compiler: &interface::Compiler) {
|
||||
assert!(sess.opts.unstable_opts.link_only);
|
||||
if let Input::File(file) = &sess.io.input {
|
||||
let outputs = compiler.build_output_filenames(sess, &[]);
|
||||
let rlink_data = fs::read(file).unwrap_or_else(|err| {
|
||||
sess.emit_fatal(RlinkUnableToRead { err });
|
||||
});
|
||||
let codegen_results = match CodegenResults::deserialize_rlink(sess, rlink_data) {
|
||||
Ok(codegen) => codegen,
|
||||
Err(err) => {
|
||||
match err {
|
||||
CodegenErrors::WrongFileType => sess.emit_fatal(RLinkWrongFileType),
|
||||
CodegenErrors::EmptyVersionNumber => sess.emit_fatal(RLinkEmptyVersionNumber),
|
||||
CodegenErrors::EncodingVersionMismatch { version_array, rlink_version } => sess
|
||||
.emit_fatal(RLinkEncodingVersionMismatch { version_array, rlink_version }),
|
||||
CodegenErrors::RustcVersionMismatch { rustc_version } => {
|
||||
sess.emit_fatal(RLinkRustcVersionMismatch {
|
||||
rustc_version,
|
||||
current_version: sess.cfg_version,
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
let result = compiler.codegen_backend().link(sess, codegen_results, &outputs);
|
||||
abort_on_err(result, sess);
|
||||
} else {
|
||||
Compilation::Continue
|
||||
sess.emit_fatal(RlinkNotAFile {})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -720,25 +679,25 @@ fn list_metadata(
|
|||
handler: &EarlyErrorHandler,
|
||||
sess: &Session,
|
||||
metadata_loader: &dyn MetadataLoader,
|
||||
) -> Compilation {
|
||||
let ls_kinds = &sess.opts.unstable_opts.ls;
|
||||
if !ls_kinds.is_empty() {
|
||||
match sess.io.input {
|
||||
Input::File(ref ifile) => {
|
||||
let path = &(*ifile);
|
||||
let mut v = Vec::new();
|
||||
locator::list_file_metadata(&sess.target, path, metadata_loader, &mut v, ls_kinds)
|
||||
.unwrap();
|
||||
safe_println!("{}", String::from_utf8(v).unwrap());
|
||||
}
|
||||
Input::Str { .. } => {
|
||||
handler.early_error("cannot list metadata for stdin");
|
||||
}
|
||||
) {
|
||||
match sess.io.input {
|
||||
Input::File(ref ifile) => {
|
||||
let path = &(*ifile);
|
||||
let mut v = Vec::new();
|
||||
locator::list_file_metadata(
|
||||
&sess.target,
|
||||
path,
|
||||
metadata_loader,
|
||||
&mut v,
|
||||
&sess.opts.unstable_opts.ls,
|
||||
)
|
||||
.unwrap();
|
||||
safe_println!("{}", String::from_utf8(v).unwrap());
|
||||
}
|
||||
Input::Str { .. } => {
|
||||
handler.early_error("cannot list metadata for stdin");
|
||||
}
|
||||
return Compilation::Stop;
|
||||
}
|
||||
|
||||
Compilation::Continue
|
||||
}
|
||||
|
||||
fn print_crate_info(
|
||||
|
|
@ -991,7 +950,7 @@ the command line flag directly.
|
|||
}
|
||||
|
||||
/// Write to stdout lint command options, together with a list of all available lints
|
||||
pub fn describe_lints(sess: &Session, lint_store: &LintStore, loaded_lints: bool) {
|
||||
pub fn describe_lints(sess: &Session) {
|
||||
safe_println!(
|
||||
"
|
||||
Available lint options:
|
||||
|
|
@ -1017,6 +976,7 @@ Available lint options:
|
|||
lints
|
||||
}
|
||||
|
||||
let lint_store = unerased_lint_store(sess);
|
||||
let (loaded, builtin): (Vec<_>, _) =
|
||||
lint_store.get_lints().iter().cloned().partition(|&lint| lint.is_loaded);
|
||||
let loaded = sort_lints(sess, loaded);
|
||||
|
|
@ -1094,7 +1054,7 @@ Available lint options:
|
|||
|
||||
print_lint_groups(builtin_groups, true);
|
||||
|
||||
match (loaded_lints, loaded.len(), loaded_groups.len()) {
|
||||
match (sess.registered_lints, loaded.len(), loaded_groups.len()) {
|
||||
(false, 0, _) | (false, _, 0) => {
|
||||
safe_println!("Lint tools like Clippy can load additional lints and lint groups.");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use rustc_middle::mir::{write_mir_graphviz, write_mir_pretty};
|
|||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_session::config::{OutFileName, PpHirMode, PpMode, PpSourceMode};
|
||||
use rustc_session::Session;
|
||||
use rustc_smir::rustc_internal::pretty::write_smir_pretty;
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::FileName;
|
||||
|
||||
|
|
@ -325,6 +326,11 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) {
|
|||
write_mir_graphviz(ex.tcx(), None, &mut out).unwrap();
|
||||
String::from_utf8(out).unwrap()
|
||||
}
|
||||
StableMir => {
|
||||
let mut out = Vec::new();
|
||||
write_smir_pretty(ex.tcx(), &mut out).unwrap();
|
||||
String::from_utf8(out).unwrap()
|
||||
}
|
||||
ThirTree => {
|
||||
let tcx = ex.tcx();
|
||||
let mut out = String::new();
|
||||
|
|
|
|||
|
|
@ -777,17 +777,15 @@ impl Diagnostic {
|
|||
applicability: Applicability,
|
||||
style: SuggestionStyle,
|
||||
) -> &mut Self {
|
||||
let mut suggestions: Vec<_> = suggestions.into_iter().collect();
|
||||
suggestions.sort();
|
||||
|
||||
debug_assert!(
|
||||
!(sp.is_empty() && suggestions.iter().any(|suggestion| suggestion.is_empty())),
|
||||
"Span must not be empty and have no suggestion"
|
||||
);
|
||||
|
||||
let substitutions = suggestions
|
||||
.into_iter()
|
||||
.map(|snippet| Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] })
|
||||
.map(|snippet| {
|
||||
debug_assert!(
|
||||
!(sp.is_empty() && snippet.is_empty()),
|
||||
"Span must not be empty and have no suggestion"
|
||||
);
|
||||
Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] }
|
||||
})
|
||||
.collect();
|
||||
self.push_suggestion(CodeSuggestion {
|
||||
substitutions,
|
||||
|
|
|
|||
|
|
@ -145,6 +145,25 @@ impl JsonEmitter {
|
|||
pub fn ignored_directories_in_source_blocks(self, value: Vec<String>) -> Self {
|
||||
Self { ignored_directories_in_source_blocks: value, ..self }
|
||||
}
|
||||
|
||||
fn emit(&mut self, val: EmitTyped<'_>) -> io::Result<()> {
|
||||
if self.pretty {
|
||||
serde_json::to_writer_pretty(&mut *self.dst, &val)?
|
||||
} else {
|
||||
serde_json::to_writer(&mut *self.dst, &val)?
|
||||
};
|
||||
self.dst.write_all(b"\n")?;
|
||||
self.dst.flush()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(tag = "$message_type", rename_all = "snake_case")]
|
||||
enum EmitTyped<'a> {
|
||||
Diagnostic(Diagnostic),
|
||||
Artifact(ArtifactNotification<'a>),
|
||||
FutureIncompat(FutureIncompatReport<'a>),
|
||||
UnusedExtern(UnusedExterns<'a, 'a, 'a>),
|
||||
}
|
||||
|
||||
impl Translate for JsonEmitter {
|
||||
|
|
@ -160,12 +179,7 @@ impl Translate for JsonEmitter {
|
|||
impl Emitter for JsonEmitter {
|
||||
fn emit_diagnostic(&mut self, diag: &crate::Diagnostic) {
|
||||
let data = Diagnostic::from_errors_diagnostic(diag, self);
|
||||
let result = if self.pretty {
|
||||
writeln!(&mut self.dst, "{}", serde_json::to_string_pretty(&data).unwrap())
|
||||
} else {
|
||||
writeln!(&mut self.dst, "{}", serde_json::to_string(&data).unwrap())
|
||||
}
|
||||
.and_then(|_| self.dst.flush());
|
||||
let result = self.emit(EmitTyped::Diagnostic(data));
|
||||
if let Err(e) = result {
|
||||
panic!("failed to print diagnostics: {e:?}");
|
||||
}
|
||||
|
|
@ -173,34 +187,28 @@ impl Emitter for JsonEmitter {
|
|||
|
||||
fn emit_artifact_notification(&mut self, path: &Path, artifact_type: &str) {
|
||||
let data = ArtifactNotification { artifact: path, emit: artifact_type };
|
||||
let result = if self.pretty {
|
||||
writeln!(&mut self.dst, "{}", serde_json::to_string_pretty(&data).unwrap())
|
||||
} else {
|
||||
writeln!(&mut self.dst, "{}", serde_json::to_string(&data).unwrap())
|
||||
}
|
||||
.and_then(|_| self.dst.flush());
|
||||
let result = self.emit(EmitTyped::Artifact(data));
|
||||
if let Err(e) = result {
|
||||
panic!("failed to print notification: {e:?}");
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_future_breakage_report(&mut self, diags: Vec<crate::Diagnostic>) {
|
||||
let data: Vec<FutureBreakageItem> = diags
|
||||
let data: Vec<FutureBreakageItem<'_>> = diags
|
||||
.into_iter()
|
||||
.map(|mut diag| {
|
||||
if diag.level == crate::Level::Allow {
|
||||
diag.level = crate::Level::Warning(None);
|
||||
}
|
||||
FutureBreakageItem { diagnostic: Diagnostic::from_errors_diagnostic(&diag, self) }
|
||||
FutureBreakageItem {
|
||||
diagnostic: EmitTyped::Diagnostic(Diagnostic::from_errors_diagnostic(
|
||||
&diag, self,
|
||||
)),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let report = FutureIncompatReport { future_incompat_report: data };
|
||||
let result = if self.pretty {
|
||||
writeln!(&mut self.dst, "{}", serde_json::to_string_pretty(&report).unwrap())
|
||||
} else {
|
||||
writeln!(&mut self.dst, "{}", serde_json::to_string(&report).unwrap())
|
||||
}
|
||||
.and_then(|_| self.dst.flush());
|
||||
let result = self.emit(EmitTyped::FutureIncompat(report));
|
||||
if let Err(e) = result {
|
||||
panic!("failed to print future breakage report: {e:?}");
|
||||
}
|
||||
|
|
@ -209,12 +217,7 @@ impl Emitter for JsonEmitter {
|
|||
fn emit_unused_externs(&mut self, lint_level: rustc_lint_defs::Level, unused_externs: &[&str]) {
|
||||
let lint_level = lint_level.as_str();
|
||||
let data = UnusedExterns { lint_level, unused_extern_names: unused_externs };
|
||||
let result = if self.pretty {
|
||||
writeln!(&mut self.dst, "{}", serde_json::to_string_pretty(&data).unwrap())
|
||||
} else {
|
||||
writeln!(&mut self.dst, "{}", serde_json::to_string(&data).unwrap())
|
||||
}
|
||||
.and_then(|_| self.dst.flush());
|
||||
let result = self.emit(EmitTyped::UnusedExtern(data));
|
||||
if let Err(e) = result {
|
||||
panic!("failed to print unused externs: {e:?}");
|
||||
}
|
||||
|
|
@ -313,13 +316,15 @@ struct ArtifactNotification<'a> {
|
|||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct FutureBreakageItem {
|
||||
diagnostic: Diagnostic,
|
||||
struct FutureBreakageItem<'a> {
|
||||
// Always EmitTyped::Diagnostic, but we want to make sure it gets serialized
|
||||
// with "$message_type".
|
||||
diagnostic: EmitTyped<'a>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct FutureIncompatReport {
|
||||
future_incompat_report: Vec<FutureBreakageItem>,
|
||||
struct FutureIncompatReport<'a> {
|
||||
future_incompat_report: Vec<FutureBreakageItem<'a>>,
|
||||
}
|
||||
|
||||
// NOTE: Keep this in sync with the equivalent structs in rustdoc's
|
||||
|
|
|
|||
|
|
@ -67,6 +67,12 @@ pub(super) fn failed_to_match_macro<'cx>(
|
|||
&& (matches!(expected_token.kind, TokenKind::Interpolated(_))
|
||||
|| matches!(token.kind, TokenKind::Interpolated(_)))
|
||||
{
|
||||
if let TokenKind::Interpolated(node) = &expected_token.kind {
|
||||
err.span_label(node.1, "");
|
||||
}
|
||||
if let TokenKind::Interpolated(node) = &token.kind {
|
||||
err.span_label(node.1, "");
|
||||
}
|
||||
err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens");
|
||||
err.note("see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information");
|
||||
|
||||
|
|
|
|||
|
|
@ -397,7 +397,7 @@ pub(crate) enum NamedMatch {
|
|||
MatchedTokenTree(rustc_ast::tokenstream::TokenTree),
|
||||
|
||||
// A metavar match of any type other than `tt`.
|
||||
MatchedNonterminal(Lrc<Nonterminal>),
|
||||
MatchedNonterminal(Lrc<(Nonterminal, rustc_span::Span)>),
|
||||
}
|
||||
|
||||
/// Performs a token equality check, ignoring syntax context (that is, an unhygienic comparison)
|
||||
|
|
@ -692,7 +692,7 @@ impl TtParser {
|
|||
Ok(nt) => nt,
|
||||
};
|
||||
let m = match nt {
|
||||
ParseNtResult::Nt(nt) => MatchedNonterminal(Lrc::new(nt)),
|
||||
ParseNtResult::Nt(nt) => MatchedNonterminal(Lrc::new((nt, span))),
|
||||
ParseNtResult::Tt(tt) => MatchedTokenTree(tt),
|
||||
};
|
||||
mp.push_match(next_metavar, seq_depth, m);
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ impl MultiItemModifier for DeriveProcMacro {
|
|||
Annotatable::Stmt(stmt) => token::NtStmt(stmt),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
TokenStream::token_alone(token::Interpolated(Lrc::new(nt)), DUMMY_SP)
|
||||
TokenStream::token_alone(token::Interpolated(Lrc::new((nt, span))), DUMMY_SP)
|
||||
} else {
|
||||
item.to_tokens()
|
||||
};
|
||||
|
|
|
|||
|
|
@ -226,18 +226,23 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
|
|||
}));
|
||||
}
|
||||
|
||||
Interpolated(nt) if let NtIdent(ident, is_raw) = *nt => trees
|
||||
.push(TokenTree::Ident(Ident { sym: ident.name, is_raw, span: ident.span })),
|
||||
Interpolated(ref nt) if let NtIdent(ident, is_raw) = &nt.0 => {
|
||||
trees.push(TokenTree::Ident(Ident {
|
||||
sym: ident.name,
|
||||
is_raw: *is_raw,
|
||||
span: ident.span,
|
||||
}))
|
||||
}
|
||||
|
||||
Interpolated(nt) => {
|
||||
let stream = TokenStream::from_nonterminal_ast(&nt);
|
||||
let stream = TokenStream::from_nonterminal_ast(&nt.0);
|
||||
// A hack used to pass AST fragments to attribute and derive
|
||||
// macros as a single nonterminal token instead of a token
|
||||
// stream. Such token needs to be "unwrapped" and not
|
||||
// represented as a delimited group.
|
||||
// FIXME: It needs to be removed, but there are some
|
||||
// compatibility issues (see #73345).
|
||||
if crate::base::nt_pretty_printing_compatibility_hack(&nt, rustc.sess()) {
|
||||
if crate::base::nt_pretty_printing_compatibility_hack(&nt.0, rustc.sess()) {
|
||||
trees.extend(Self::from_internal((stream, rustc)));
|
||||
} else {
|
||||
trees.push(TokenTree::Group(Group {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ macro_rules! arena_types {
|
|||
($macro:path) => (
|
||||
$macro!([
|
||||
// HIR types
|
||||
[] hir_krate: rustc_hir::Crate<'tcx>,
|
||||
[] asm_template: rustc_ast::InlineAsmTemplatePiece,
|
||||
[] attribute: rustc_ast::Attribute,
|
||||
[] owner_info: rustc_hir::OwnerInfo<'tcx>,
|
||||
|
|
|
|||
|
|
@ -13,8 +13,7 @@ use std::array::IntoIter;
|
|||
use std::fmt::Debug;
|
||||
|
||||
/// Encodes if a `DefKind::Ctor` is the constructor of an enum variant or a struct.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
|
||||
#[derive(HashStable_Generic)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug, HashStable_Generic)]
|
||||
pub enum CtorOf {
|
||||
/// This `DefKind::Ctor` is a synthesized constructor of a tuple or unit struct.
|
||||
Struct,
|
||||
|
|
@ -23,8 +22,7 @@ pub enum CtorOf {
|
|||
}
|
||||
|
||||
/// What kind of constructor something is.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
|
||||
#[derive(HashStable_Generic)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug, HashStable_Generic)]
|
||||
pub enum CtorKind {
|
||||
/// Constructor function automatically created by a tuple struct/variant.
|
||||
Fn,
|
||||
|
|
@ -33,8 +31,7 @@ pub enum CtorKind {
|
|||
}
|
||||
|
||||
/// An attribute that is not a macro; e.g., `#[inline]` or `#[rustfmt::skip]`.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
|
||||
#[derive(HashStable_Generic)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug, HashStable_Generic)]
|
||||
pub enum NonMacroAttrKind {
|
||||
/// Single-segment attribute defined by the language (`#[inline]`)
|
||||
Builtin(Symbol),
|
||||
|
|
@ -48,8 +45,7 @@ pub enum NonMacroAttrKind {
|
|||
}
|
||||
|
||||
/// What kind of definition something is; e.g., `mod` vs `struct`.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
|
||||
#[derive(HashStable_Generic)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug, HashStable_Generic)]
|
||||
pub enum DefKind {
|
||||
// Type namespace
|
||||
Mod,
|
||||
|
|
@ -299,8 +295,7 @@ impl DefKind {
|
|||
/// - the call to `str_to_string` will resolve to [`Res::Def`], with the [`DefId`]
|
||||
/// pointing to the definition of `str_to_string` in the current crate.
|
||||
//
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
|
||||
#[derive(HashStable_Generic)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug, HashStable_Generic)]
|
||||
pub enum Res<Id = hir::HirId> {
|
||||
/// Definition having a unique ID (`DefId`), corresponds to something defined in user code.
|
||||
///
|
||||
|
|
@ -591,6 +586,8 @@ impl NonMacroAttrKind {
|
|||
}
|
||||
}
|
||||
|
||||
// Currently trivial, but exists in case a new kind is added in the future whose name starts
|
||||
// with a vowel.
|
||||
pub fn article(self) -> &'static str {
|
||||
"a"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
|||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
use rustc_error_messages::MultiSpan;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_macros::HashStable_Generic;
|
||||
use rustc_span::hygiene::MacroKind;
|
||||
|
|
@ -76,13 +75,6 @@ impl ParamName {
|
|||
ParamName::Fresh | ParamName::Error => Ident::with_dummy_span(kw::UnderscoreLifetime),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn normalize_to_macros_2_0(&self) -> ParamName {
|
||||
match *self {
|
||||
ParamName::Plain(ident) => ParamName::Plain(ident.normalize_to_macros_2_0()),
|
||||
param_name => param_name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)]
|
||||
|
|
@ -116,7 +108,7 @@ pub enum LifetimeName {
|
|||
}
|
||||
|
||||
impl LifetimeName {
|
||||
pub fn is_elided(&self) -> bool {
|
||||
fn is_elided(&self) -> bool {
|
||||
match self {
|
||||
LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Infer => true,
|
||||
|
||||
|
|
@ -289,10 +281,6 @@ impl GenericArg<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_synthetic(&self) -> bool {
|
||||
matches!(self, GenericArg::Lifetime(lifetime) if lifetime.ident == Ident::empty())
|
||||
}
|
||||
|
||||
pub fn descr(&self) -> &'static str {
|
||||
match self {
|
||||
GenericArg::Lifetime(_) => "lifetime",
|
||||
|
|
@ -368,11 +356,6 @@ impl<'hir> GenericArgs<'hir> {
|
|||
panic!("GenericArgs::inputs: not a `Fn(T) -> U`");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn has_type_params(&self) -> bool {
|
||||
self.args.iter().any(|arg| matches!(arg, GenericArg::Type(_)))
|
||||
}
|
||||
|
||||
pub fn has_err(&self) -> bool {
|
||||
self.args.iter().any(|arg| match arg {
|
||||
GenericArg::Type(ty) => matches!(ty.kind, TyKind::Err(_)),
|
||||
|
|
@ -383,11 +366,6 @@ impl<'hir> GenericArgs<'hir> {
|
|||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn num_type_params(&self) -> usize {
|
||||
self.args.iter().filter(|arg| matches!(arg, GenericArg::Type(_))).count()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn num_lifetime_params(&self) -> usize {
|
||||
self.args.iter().filter(|arg| matches!(arg, GenericArg::Lifetime(_))).count()
|
||||
|
|
@ -589,14 +567,6 @@ impl<'hir> Generics<'hir> {
|
|||
self.params.iter().find(|¶m| name == param.name.ident().name)
|
||||
}
|
||||
|
||||
pub fn spans(&self) -> MultiSpan {
|
||||
if self.params.is_empty() {
|
||||
self.span.into()
|
||||
} else {
|
||||
self.params.iter().map(|p| p.span).collect::<Vec<Span>>().into()
|
||||
}
|
||||
}
|
||||
|
||||
/// If there are generic parameters, return where to introduce a new one.
|
||||
pub fn span_for_lifetime_suggestion(&self) -> Option<Span> {
|
||||
if let Some(first) = self.params.first()
|
||||
|
|
@ -679,7 +649,7 @@ impl<'hir> Generics<'hir> {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn span_for_predicate_removal(&self, pos: usize) -> Span {
|
||||
fn span_for_predicate_removal(&self, pos: usize) -> Span {
|
||||
let predicate = &self.predicates[pos];
|
||||
let span = predicate.span();
|
||||
|
||||
|
|
@ -812,7 +782,7 @@ pub struct WhereRegionPredicate<'hir> {
|
|||
|
||||
impl<'hir> WhereRegionPredicate<'hir> {
|
||||
/// Returns `true` if `param_def_id` matches the `lifetime` of this predicate.
|
||||
pub fn is_param_bound(&self, param_def_id: LocalDefId) -> bool {
|
||||
fn is_param_bound(&self, param_def_id: LocalDefId) -> bool {
|
||||
self.lifetime.res == LifetimeName::Param(param_def_id)
|
||||
}
|
||||
}
|
||||
|
|
@ -869,7 +839,7 @@ pub struct OwnerNodes<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> OwnerNodes<'tcx> {
|
||||
pub fn node(&self) -> OwnerNode<'tcx> {
|
||||
fn node(&self) -> OwnerNode<'tcx> {
|
||||
use rustc_index::Idx;
|
||||
let node = self.nodes[ItemLocalId::new(0)].as_ref().unwrap().node;
|
||||
let node = node.as_owner().unwrap(); // Indexing must ensure it is an OwnerNode.
|
||||
|
|
@ -1272,10 +1242,6 @@ impl BinOpKind {
|
|||
matches!(self, BinOpKind::And | BinOpKind::Or)
|
||||
}
|
||||
|
||||
pub fn is_shift(self) -> bool {
|
||||
matches!(self, BinOpKind::Shl | BinOpKind::Shr)
|
||||
}
|
||||
|
||||
pub fn is_comparison(self) -> bool {
|
||||
match self {
|
||||
BinOpKind::Eq
|
||||
|
|
@ -1516,8 +1482,7 @@ impl<'hir> Body<'hir> {
|
|||
}
|
||||
|
||||
/// The type of source expression that caused this coroutine to be created.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Copy, Hash)]
|
||||
#[derive(HashStable_Generic, Encodable, Decodable)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Copy, Hash, HashStable_Generic, Encodable, Decodable)]
|
||||
pub enum CoroutineKind {
|
||||
/// An explicit `async` block or the body of an async function.
|
||||
Async(CoroutineSource),
|
||||
|
|
@ -1558,8 +1523,7 @@ impl fmt::Display for CoroutineKind {
|
|||
///
|
||||
/// This helps error messages but is also used to drive coercions in
|
||||
/// type-checking (see #60424).
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, Copy)]
|
||||
#[derive(HashStable_Generic, Encodable, Decodable)]
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, Copy, HashStable_Generic, Encodable, Decodable)]
|
||||
pub enum CoroutineSource {
|
||||
/// An explicit `async`/`gen` block written by the user.
|
||||
Block,
|
||||
|
|
@ -2117,16 +2081,6 @@ impl<'hir> QPath<'hir> {
|
|||
QPath::LangItem(_, span, _) => span,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the span of the last segment of this `QPath`. For example, `method` in
|
||||
/// `<() as Trait>::method`.
|
||||
pub fn last_segment_span(&self) -> Span {
|
||||
match *self {
|
||||
QPath::Resolved(_, path) => path.segments.last().unwrap().ident.span,
|
||||
QPath::TypeRelative(_, segment) => segment.ident.span,
|
||||
QPath::LangItem(_, span, _) => span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Hints at the original code for a let statement.
|
||||
|
|
@ -2153,8 +2107,7 @@ pub enum LocalSource {
|
|||
}
|
||||
|
||||
/// Hints at the original code for a `match _ { .. }`.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
#[derive(HashStable_Generic, Encodable, Decodable)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic, Encodable, Decodable)]
|
||||
pub enum MatchSource {
|
||||
/// A `match _ { .. }`.
|
||||
Normal,
|
||||
|
|
@ -2314,6 +2267,35 @@ pub struct TraitItem<'hir> {
|
|||
pub defaultness: Defaultness,
|
||||
}
|
||||
|
||||
macro_rules! expect_methods_self_kind {
|
||||
( $( $name:ident, $ret_ty:ty, $pat:pat, $ret_val:expr; )* ) => {
|
||||
$(
|
||||
#[track_caller]
|
||||
pub fn $name(&self) -> $ret_ty {
|
||||
let $pat = &self.kind else { expect_failed(stringify!($ident), self) };
|
||||
$ret_val
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! expect_methods_self {
|
||||
( $( $name:ident, $ret_ty:ty, $pat:pat, $ret_val:expr; )* ) => {
|
||||
$(
|
||||
#[track_caller]
|
||||
pub fn $name(&self) -> $ret_ty {
|
||||
let $pat = self else { expect_failed(stringify!($ident), self) };
|
||||
$ret_val
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn expect_failed<T: fmt::Debug>(ident: &'static str, found: T) -> ! {
|
||||
panic!("{ident}: found {found:?}")
|
||||
}
|
||||
|
||||
impl<'hir> TraitItem<'hir> {
|
||||
#[inline]
|
||||
pub fn hir_id(&self) -> HirId {
|
||||
|
|
@ -2325,30 +2307,15 @@ impl<'hir> TraitItem<'hir> {
|
|||
TraitItemId { owner_id: self.owner_id }
|
||||
}
|
||||
|
||||
/// Expect an [`TraitItemKind::Const`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_const(&self) -> (&'hir Ty<'hir>, Option<BodyId>) {
|
||||
let TraitItemKind::Const(ty, body) = self.kind else { self.expect_failed("a constant") };
|
||||
(ty, body)
|
||||
}
|
||||
expect_methods_self_kind! {
|
||||
expect_const, (&'hir Ty<'hir>, Option<BodyId>),
|
||||
TraitItemKind::Const(ty, body), (ty, *body);
|
||||
|
||||
/// Expect an [`TraitItemKind::Fn`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_fn(&self) -> (&FnSig<'hir>, &TraitFn<'hir>) {
|
||||
let TraitItemKind::Fn(ty, trfn) = &self.kind else { self.expect_failed("a function") };
|
||||
(ty, trfn)
|
||||
}
|
||||
expect_fn, (&FnSig<'hir>, &TraitFn<'hir>),
|
||||
TraitItemKind::Fn(ty, trfn), (ty, trfn);
|
||||
|
||||
/// Expect an [`TraitItemKind::Type`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_type(&self) -> (GenericBounds<'hir>, Option<&'hir Ty<'hir>>) {
|
||||
let TraitItemKind::Type(bounds, ty) = self.kind else { self.expect_failed("a type") };
|
||||
(bounds, ty)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn expect_failed(&self, expected: &'static str) -> ! {
|
||||
panic!("expected {expected} item, found {self:?}")
|
||||
expect_type, (GenericBounds<'hir>, Option<&'hir Ty<'hir>>),
|
||||
TraitItemKind::Type(bounds, ty), (bounds, *ty);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2413,30 +2380,10 @@ impl<'hir> ImplItem<'hir> {
|
|||
ImplItemId { owner_id: self.owner_id }
|
||||
}
|
||||
|
||||
/// Expect an [`ImplItemKind::Const`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_const(&self) -> (&'hir Ty<'hir>, BodyId) {
|
||||
let ImplItemKind::Const(ty, body) = self.kind else { self.expect_failed("a constant") };
|
||||
(ty, body)
|
||||
}
|
||||
|
||||
/// Expect an [`ImplItemKind::Fn`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_fn(&self) -> (&FnSig<'hir>, BodyId) {
|
||||
let ImplItemKind::Fn(ty, body) = &self.kind else { self.expect_failed("a function") };
|
||||
(ty, *body)
|
||||
}
|
||||
|
||||
/// Expect an [`ImplItemKind::Type`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_type(&self) -> &'hir Ty<'hir> {
|
||||
let ImplItemKind::Type(ty) = self.kind else { self.expect_failed("a type") };
|
||||
ty
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn expect_failed(&self, expected: &'static str) -> ! {
|
||||
panic!("expected {expected} item, found {self:?}")
|
||||
expect_methods_self_kind! {
|
||||
expect_const, (&'hir Ty<'hir>, BodyId), ImplItemKind::Const(ty, body), (ty, *body);
|
||||
expect_fn, (&FnSig<'hir>, BodyId), ImplItemKind::Fn(ty, body), (ty, *body);
|
||||
expect_type, &'hir Ty<'hir>, ImplItemKind::Type(ty), ty;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2579,8 +2526,7 @@ impl<'hir> Ty<'hir> {
|
|||
}
|
||||
|
||||
/// Not represented directly in the AST; referred to by name through a `ty_path`.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
|
||||
#[derive(HashStable_Generic)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, Debug, HashStable_Generic)]
|
||||
pub enum PrimTy {
|
||||
Int(IntTy),
|
||||
Uint(UintTy),
|
||||
|
|
@ -2860,8 +2806,7 @@ impl ImplicitSelfKind {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
|
||||
#[derive(HashStable_Generic)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub enum IsAsync {
|
||||
Async(Span),
|
||||
NotAsync,
|
||||
|
|
@ -3124,134 +3069,51 @@ impl<'hir> Item<'hir> {
|
|||
ItemId { owner_id: self.owner_id }
|
||||
}
|
||||
|
||||
/// Expect an [`ItemKind::ExternCrate`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_extern_crate(&self) -> Option<Symbol> {
|
||||
let ItemKind::ExternCrate(s) = self.kind else { self.expect_failed("an extern crate") };
|
||||
s
|
||||
}
|
||||
expect_methods_self_kind! {
|
||||
expect_extern_crate, Option<Symbol>, ItemKind::ExternCrate(s), *s;
|
||||
|
||||
/// Expect an [`ItemKind::Use`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_use(&self) -> (&'hir UsePath<'hir>, UseKind) {
|
||||
let ItemKind::Use(p, uk) = self.kind else { self.expect_failed("a use") };
|
||||
(p, uk)
|
||||
}
|
||||
expect_use, (&'hir UsePath<'hir>, UseKind), ItemKind::Use(p, uk), (p, *uk);
|
||||
|
||||
/// Expect an [`ItemKind::Static`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_static(&self) -> (&'hir Ty<'hir>, Mutability, BodyId) {
|
||||
let ItemKind::Static(ty, mutbl, body) = self.kind else { self.expect_failed("a static") };
|
||||
(ty, mutbl, body)
|
||||
}
|
||||
/// Expect an [`ItemKind::Const`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_const(&self) -> (&'hir Ty<'hir>, &'hir Generics<'hir>, BodyId) {
|
||||
let ItemKind::Const(ty, gen, body) = self.kind else { self.expect_failed("a constant") };
|
||||
(ty, gen, body)
|
||||
}
|
||||
/// Expect an [`ItemKind::Fn`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_fn(&self) -> (&FnSig<'hir>, &'hir Generics<'hir>, BodyId) {
|
||||
let ItemKind::Fn(sig, gen, body) = &self.kind else { self.expect_failed("a function") };
|
||||
(sig, gen, *body)
|
||||
}
|
||||
expect_static, (&'hir Ty<'hir>, Mutability, BodyId),
|
||||
ItemKind::Static(ty, mutbl, body), (ty, *mutbl, *body);
|
||||
|
||||
/// Expect an [`ItemKind::Macro`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_macro(&self) -> (&ast::MacroDef, MacroKind) {
|
||||
let ItemKind::Macro(def, mk) = &self.kind else { self.expect_failed("a macro") };
|
||||
(def, *mk)
|
||||
}
|
||||
expect_const, (&'hir Ty<'hir>, &'hir Generics<'hir>, BodyId),
|
||||
ItemKind::Const(ty, gen, body), (ty, gen, *body);
|
||||
|
||||
/// Expect an [`ItemKind::Mod`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_mod(&self) -> &'hir Mod<'hir> {
|
||||
let ItemKind::Mod(m) = self.kind else { self.expect_failed("a module") };
|
||||
m
|
||||
}
|
||||
expect_fn, (&FnSig<'hir>, &'hir Generics<'hir>, BodyId),
|
||||
ItemKind::Fn(sig, gen, body), (sig, gen, *body);
|
||||
|
||||
/// Expect an [`ItemKind::ForeignMod`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_foreign_mod(&self) -> (Abi, &'hir [ForeignItemRef]) {
|
||||
let ItemKind::ForeignMod { abi, items } = self.kind else {
|
||||
self.expect_failed("a foreign module")
|
||||
};
|
||||
(abi, items)
|
||||
}
|
||||
expect_macro, (&ast::MacroDef, MacroKind), ItemKind::Macro(def, mk), (def, *mk);
|
||||
|
||||
/// Expect an [`ItemKind::GlobalAsm`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_global_asm(&self) -> &'hir InlineAsm<'hir> {
|
||||
let ItemKind::GlobalAsm(asm) = self.kind else { self.expect_failed("a global asm") };
|
||||
asm
|
||||
}
|
||||
expect_mod, &'hir Mod<'hir>, ItemKind::Mod(m), m;
|
||||
|
||||
/// Expect an [`ItemKind::TyAlias`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_ty_alias(&self) -> (&'hir Ty<'hir>, &'hir Generics<'hir>) {
|
||||
let ItemKind::TyAlias(ty, gen) = self.kind else { self.expect_failed("a type alias") };
|
||||
(ty, gen)
|
||||
}
|
||||
expect_foreign_mod, (Abi, &'hir [ForeignItemRef]),
|
||||
ItemKind::ForeignMod { abi, items }, (*abi, items);
|
||||
|
||||
/// Expect an [`ItemKind::OpaqueTy`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_opaque_ty(&self) -> &OpaqueTy<'hir> {
|
||||
let ItemKind::OpaqueTy(ty) = &self.kind else { self.expect_failed("an opaque type") };
|
||||
ty
|
||||
}
|
||||
expect_global_asm, &'hir InlineAsm<'hir>, ItemKind::GlobalAsm(asm), asm;
|
||||
|
||||
/// Expect an [`ItemKind::Enum`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_enum(&self) -> (&EnumDef<'hir>, &'hir Generics<'hir>) {
|
||||
let ItemKind::Enum(def, gen) = &self.kind else { self.expect_failed("an enum") };
|
||||
(def, gen)
|
||||
}
|
||||
expect_ty_alias, (&'hir Ty<'hir>, &'hir Generics<'hir>),
|
||||
ItemKind::TyAlias(ty, gen), (ty, gen);
|
||||
|
||||
/// Expect an [`ItemKind::Struct`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_struct(&self) -> (&VariantData<'hir>, &'hir Generics<'hir>) {
|
||||
let ItemKind::Struct(data, gen) = &self.kind else { self.expect_failed("a struct") };
|
||||
(data, gen)
|
||||
}
|
||||
expect_opaque_ty, &OpaqueTy<'hir>, ItemKind::OpaqueTy(ty), ty;
|
||||
|
||||
/// Expect an [`ItemKind::Union`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_union(&self) -> (&VariantData<'hir>, &'hir Generics<'hir>) {
|
||||
let ItemKind::Union(data, gen) = &self.kind else { self.expect_failed("a union") };
|
||||
(data, gen)
|
||||
}
|
||||
expect_enum, (&EnumDef<'hir>, &'hir Generics<'hir>), ItemKind::Enum(def, gen), (def, gen);
|
||||
|
||||
/// Expect an [`ItemKind::Trait`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_trait(
|
||||
self,
|
||||
) -> (IsAuto, Unsafety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]) {
|
||||
let ItemKind::Trait(is_auto, unsafety, gen, bounds, items) = self.kind else {
|
||||
self.expect_failed("a trait")
|
||||
};
|
||||
(is_auto, unsafety, gen, bounds, items)
|
||||
}
|
||||
expect_struct, (&VariantData<'hir>, &'hir Generics<'hir>),
|
||||
ItemKind::Struct(data, gen), (data, gen);
|
||||
|
||||
/// Expect an [`ItemKind::TraitAlias`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_trait_alias(&self) -> (&'hir Generics<'hir>, GenericBounds<'hir>) {
|
||||
let ItemKind::TraitAlias(gen, bounds) = self.kind else {
|
||||
self.expect_failed("a trait alias")
|
||||
};
|
||||
(gen, bounds)
|
||||
}
|
||||
expect_union, (&VariantData<'hir>, &'hir Generics<'hir>),
|
||||
ItemKind::Union(data, gen), (data, gen);
|
||||
|
||||
/// Expect an [`ItemKind::Impl`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_impl(&self) -> &'hir Impl<'hir> {
|
||||
let ItemKind::Impl(imp) = self.kind else { self.expect_failed("an impl") };
|
||||
imp
|
||||
}
|
||||
expect_trait,
|
||||
(IsAuto, Unsafety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]),
|
||||
ItemKind::Trait(is_auto, unsafety, gen, bounds, items),
|
||||
(*is_auto, *unsafety, gen, bounds, items);
|
||||
|
||||
#[track_caller]
|
||||
fn expect_failed(&self, expected: &'static str) -> ! {
|
||||
panic!("expected {expected} item, found {self:?}")
|
||||
expect_trait_alias, (&'hir Generics<'hir>, GenericBounds<'hir>),
|
||||
ItemKind::TraitAlias(gen, bounds), (gen, bounds);
|
||||
|
||||
expect_impl, &'hir Impl<'hir>, ItemKind::Impl(imp), imp;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3280,8 +3142,7 @@ impl fmt::Display for Unsafety {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
#[derive(Encodable, Decodable, HashStable_Generic)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Encodable, Decodable, HashStable_Generic)]
|
||||
pub enum Constness {
|
||||
Const,
|
||||
NotConst,
|
||||
|
|
@ -3624,32 +3485,11 @@ impl<'hir> OwnerNode<'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn expect_item(self) -> &'hir Item<'hir> {
|
||||
match self {
|
||||
OwnerNode::Item(n) => n,
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_foreign_item(self) -> &'hir ForeignItem<'hir> {
|
||||
match self {
|
||||
OwnerNode::ForeignItem(n) => n,
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_impl_item(self) -> &'hir ImplItem<'hir> {
|
||||
match self {
|
||||
OwnerNode::ImplItem(n) => n,
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_trait_item(self) -> &'hir TraitItem<'hir> {
|
||||
match self {
|
||||
OwnerNode::TraitItem(n) => n,
|
||||
_ => panic!(),
|
||||
}
|
||||
expect_methods_self! {
|
||||
expect_item, &'hir Item<'hir>, OwnerNode::Item(n), n;
|
||||
expect_foreign_item, &'hir ForeignItem<'hir>, OwnerNode::ForeignItem(n), n;
|
||||
expect_impl_item, &'hir ImplItem<'hir>, OwnerNode::ImplItem(n), n;
|
||||
expect_trait_item, &'hir TraitItem<'hir>, OwnerNode::TraitItem(n), n;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3902,196 +3742,33 @@ impl<'hir> Node<'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get the fields for the tuple-constructor,
|
||||
/// if this node is a tuple constructor, otherwise None
|
||||
pub fn tuple_fields(&self) -> Option<&'hir [FieldDef<'hir>]> {
|
||||
if let Node::Ctor(&VariantData::Tuple(fields, _, _)) = self { Some(fields) } else { None }
|
||||
}
|
||||
|
||||
/// Expect a [`Node::Param`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_param(self) -> &'hir Param<'hir> {
|
||||
let Node::Param(this) = self else { self.expect_failed("a parameter") };
|
||||
this
|
||||
}
|
||||
|
||||
/// Expect a [`Node::Item`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_item(self) -> &'hir Item<'hir> {
|
||||
let Node::Item(this) = self else { self.expect_failed("a item") };
|
||||
this
|
||||
}
|
||||
|
||||
/// Expect a [`Node::ForeignItem`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_foreign_item(self) -> &'hir ForeignItem<'hir> {
|
||||
let Node::ForeignItem(this) = self else { self.expect_failed("a foreign item") };
|
||||
this
|
||||
}
|
||||
|
||||
/// Expect a [`Node::TraitItem`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_trait_item(self) -> &'hir TraitItem<'hir> {
|
||||
let Node::TraitItem(this) = self else { self.expect_failed("a trait item") };
|
||||
this
|
||||
}
|
||||
|
||||
/// Expect a [`Node::ImplItem`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_impl_item(self) -> &'hir ImplItem<'hir> {
|
||||
let Node::ImplItem(this) = self else { self.expect_failed("an implementation item") };
|
||||
this
|
||||
}
|
||||
|
||||
/// Expect a [`Node::Variant`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_variant(self) -> &'hir Variant<'hir> {
|
||||
let Node::Variant(this) = self else { self.expect_failed("a variant") };
|
||||
this
|
||||
}
|
||||
|
||||
/// Expect a [`Node::Field`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_field(self) -> &'hir FieldDef<'hir> {
|
||||
let Node::Field(this) = self else { self.expect_failed("a field definition") };
|
||||
this
|
||||
}
|
||||
|
||||
/// Expect a [`Node::AnonConst`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_anon_const(self) -> &'hir AnonConst {
|
||||
let Node::AnonConst(this) = self else { self.expect_failed("an anonymous constant") };
|
||||
this
|
||||
}
|
||||
|
||||
/// Expect a [`Node::ConstBlock`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_inline_const(self) -> &'hir ConstBlock {
|
||||
let Node::ConstBlock(this) = self else { self.expect_failed("an inline constant") };
|
||||
this
|
||||
}
|
||||
|
||||
/// Expect a [`Node::Expr`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_expr(self) -> &'hir Expr<'hir> {
|
||||
let Node::Expr(this) = self else { self.expect_failed("an expression") };
|
||||
this
|
||||
}
|
||||
/// Expect a [`Node::ExprField`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_expr_field(self) -> &'hir ExprField<'hir> {
|
||||
let Node::ExprField(this) = self else { self.expect_failed("an expression field") };
|
||||
this
|
||||
}
|
||||
|
||||
/// Expect a [`Node::Stmt`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_stmt(self) -> &'hir Stmt<'hir> {
|
||||
let Node::Stmt(this) = self else { self.expect_failed("a statement") };
|
||||
this
|
||||
}
|
||||
|
||||
/// Expect a [`Node::PathSegment`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_path_segment(self) -> &'hir PathSegment<'hir> {
|
||||
let Node::PathSegment(this) = self else { self.expect_failed("a path segment") };
|
||||
this
|
||||
}
|
||||
|
||||
/// Expect a [`Node::Ty`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_ty(self) -> &'hir Ty<'hir> {
|
||||
let Node::Ty(this) = self else { self.expect_failed("a type") };
|
||||
this
|
||||
}
|
||||
|
||||
/// Expect a [`Node::TypeBinding`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_type_binding(self) -> &'hir TypeBinding<'hir> {
|
||||
let Node::TypeBinding(this) = self else { self.expect_failed("a type binding") };
|
||||
this
|
||||
}
|
||||
|
||||
/// Expect a [`Node::TraitRef`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_trait_ref(self) -> &'hir TraitRef<'hir> {
|
||||
let Node::TraitRef(this) = self else { self.expect_failed("a trait reference") };
|
||||
this
|
||||
}
|
||||
|
||||
/// Expect a [`Node::Pat`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_pat(self) -> &'hir Pat<'hir> {
|
||||
let Node::Pat(this) = self else { self.expect_failed("a pattern") };
|
||||
this
|
||||
}
|
||||
|
||||
/// Expect a [`Node::PatField`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_pat_field(self) -> &'hir PatField<'hir> {
|
||||
let Node::PatField(this) = self else { self.expect_failed("a pattern field") };
|
||||
this
|
||||
}
|
||||
|
||||
/// Expect a [`Node::Arm`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_arm(self) -> &'hir Arm<'hir> {
|
||||
let Node::Arm(this) = self else { self.expect_failed("an arm") };
|
||||
this
|
||||
}
|
||||
|
||||
/// Expect a [`Node::Block`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_block(self) -> &'hir Block<'hir> {
|
||||
let Node::Block(this) = self else { self.expect_failed("a block") };
|
||||
this
|
||||
}
|
||||
|
||||
/// Expect a [`Node::Local`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_local(self) -> &'hir Local<'hir> {
|
||||
let Node::Local(this) = self else { self.expect_failed("a local") };
|
||||
this
|
||||
}
|
||||
|
||||
/// Expect a [`Node::Ctor`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_ctor(self) -> &'hir VariantData<'hir> {
|
||||
let Node::Ctor(this) = self else { self.expect_failed("a constructor") };
|
||||
this
|
||||
}
|
||||
|
||||
/// Expect a [`Node::Lifetime`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_lifetime(self) -> &'hir Lifetime {
|
||||
let Node::Lifetime(this) = self else { self.expect_failed("a lifetime") };
|
||||
this
|
||||
}
|
||||
|
||||
/// Expect a [`Node::GenericParam`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_generic_param(self) -> &'hir GenericParam<'hir> {
|
||||
let Node::GenericParam(this) = self else { self.expect_failed("a generic parameter") };
|
||||
this
|
||||
}
|
||||
|
||||
/// Expect a [`Node::Crate`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_crate(self) -> &'hir Mod<'hir> {
|
||||
let Node::Crate(this) = self else { self.expect_failed("a crate") };
|
||||
this
|
||||
}
|
||||
|
||||
/// Expect a [`Node::Infer`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_infer(self) -> &'hir InferArg {
|
||||
let Node::Infer(this) = self else { self.expect_failed("an infer") };
|
||||
this
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn expect_failed(&self, expected: &'static str) -> ! {
|
||||
panic!("expected {expected} node, found {self:?}")
|
||||
expect_methods_self! {
|
||||
expect_param, &'hir Param<'hir>, Node::Param(n), n;
|
||||
expect_item, &'hir Item<'hir>, Node::Item(n), n;
|
||||
expect_foreign_item, &'hir ForeignItem<'hir>, Node::ForeignItem(n), n;
|
||||
expect_trait_item, &'hir TraitItem<'hir>, Node::TraitItem(n), n;
|
||||
expect_impl_item, &'hir ImplItem<'hir>, Node::ImplItem(n), n;
|
||||
expect_variant, &'hir Variant<'hir>, Node::Variant(n), n;
|
||||
expect_field, &'hir FieldDef<'hir>, Node::Field(n), n;
|
||||
expect_anon_const, &'hir AnonConst, Node::AnonConst(n), n;
|
||||
expect_inline_const, &'hir ConstBlock, Node::ConstBlock(n), n;
|
||||
expect_expr, &'hir Expr<'hir>, Node::Expr(n), n;
|
||||
expect_expr_field, &'hir ExprField<'hir>, Node::ExprField(n), n;
|
||||
expect_stmt, &'hir Stmt<'hir>, Node::Stmt(n), n;
|
||||
expect_path_segment, &'hir PathSegment<'hir>, Node::PathSegment(n), n;
|
||||
expect_ty, &'hir Ty<'hir>, Node::Ty(n), n;
|
||||
expect_type_binding, &'hir TypeBinding<'hir>, Node::TypeBinding(n), n;
|
||||
expect_trait_ref, &'hir TraitRef<'hir>, Node::TraitRef(n), n;
|
||||
expect_pat, &'hir Pat<'hir>, Node::Pat(n), n;
|
||||
expect_pat_field, &'hir PatField<'hir>, Node::PatField(n), n;
|
||||
expect_arm, &'hir Arm<'hir>, Node::Arm(n), n;
|
||||
expect_block, &'hir Block<'hir>, Node::Block(n), n;
|
||||
expect_local, &'hir Local<'hir>, Node::Local(n), n;
|
||||
expect_ctor, &'hir VariantData<'hir>, Node::Ctor(n), n;
|
||||
expect_lifetime, &'hir Lifetime, Node::Lifetime(n), n;
|
||||
expect_generic_param, &'hir GenericParam<'hir>, Node::GenericParam(n), n;
|
||||
expect_crate, &'hir Mod<'hir>, Node::Crate(n), n;
|
||||
expect_infer, &'hir InferArg, Node::Infer(n), n;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd,
|
|||
use rustc_span::{def_id::DefPathHash, HashStableContext};
|
||||
use std::fmt::{self, Debug};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Encodable, Decodable)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable)]
|
||||
pub struct OwnerId {
|
||||
pub def_id: LocalDefId,
|
||||
}
|
||||
|
|
@ -73,8 +72,7 @@ impl<CTX: HashStableContext> ToStableHashKey<CTX> for OwnerId {
|
|||
/// the `local_id` part of the `HirId` changing, which is a very useful property in
|
||||
/// incremental compilation where we have to persist things through changes to
|
||||
/// the code base.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Encodable, Decodable, HashStable_Generic)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
|
||||
#[rustc_pass_by_value]
|
||||
pub struct HirId {
|
||||
pub owner: OwnerId,
|
||||
|
|
|
|||
|
|
@ -233,7 +233,7 @@ language_item_table! {
|
|||
PanicFmt, sym::panic_fmt, panic_fmt, Target::Fn, GenericRequirement::None;
|
||||
ConstPanicFmt, sym::const_panic_fmt, const_panic_fmt, Target::Fn, GenericRequirement::None;
|
||||
PanicBoundsCheck, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn, GenericRequirement::Exact(0);
|
||||
PanicMisalignedPointerDereference, sym::panic_misaligned_pointer_dereference, panic_misaligned_pointer_dereference_fn, Target::Fn, GenericRequirement::Exact(0);
|
||||
PanicMisalignedPointerDereference, sym::panic_misaligned_pointer_dereference, panic_misaligned_pointer_dereference_fn, Target::Fn, GenericRequirement::Exact(0);
|
||||
PanicInfo, sym::panic_info, panic_info, Target::Struct, GenericRequirement::None;
|
||||
PanicLocation, sym::panic_location, panic_location, Target::Struct, GenericRequirement::None;
|
||||
PanicImpl, sym::panic_impl, panic_impl, Target::Fn, GenericRequirement::None;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
#![feature(associated_type_defaults)]
|
||||
#![feature(closure_track_caller)]
|
||||
#![feature(const_btree_len)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(never_type)]
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use crate::errors::{
|
|||
ParenthesizedFnTraitExpansion,
|
||||
};
|
||||
use crate::traits::error_reporting::report_object_safety_error;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
|
||||
use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, ErrorGuaranteed};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
|
|
@ -16,8 +16,6 @@ use rustc_span::symbol::{sym, Ident};
|
|||
use rustc_span::{Span, Symbol, DUMMY_SP};
|
||||
use rustc_trait_selection::traits::object_safety_violations_for_assoc_item;
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
/// On missing type parameters, emit an E0393 error and provide a structured suggestion using
|
||||
/// the type parameter's name as a placeholder.
|
||||
|
|
@ -504,7 +502,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
/// emit a generic note suggesting using a `where` clause to constraint instead.
|
||||
pub(crate) fn complain_about_missing_associated_types(
|
||||
&self,
|
||||
associated_types: FxHashMap<Span, BTreeSet<DefId>>,
|
||||
associated_types: FxIndexMap<Span, FxIndexSet<DefId>>,
|
||||
potential_assoc_types: Vec<Span>,
|
||||
trait_bounds: &[hir::PolyTraitRef<'_>],
|
||||
) {
|
||||
|
|
@ -514,13 +512,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
let tcx = self.tcx();
|
||||
// FIXME: Marked `mut` so that we can replace the spans further below with a more
|
||||
// appropriate one, but this should be handled earlier in the span assignment.
|
||||
let mut associated_types: FxHashMap<Span, Vec<_>> = associated_types
|
||||
let mut associated_types: FxIndexMap<Span, Vec<_>> = associated_types
|
||||
.into_iter()
|
||||
.map(|(span, def_ids)| {
|
||||
(span, def_ids.into_iter().map(|did| tcx.associated_item(did)).collect())
|
||||
})
|
||||
.collect();
|
||||
let mut names: FxHashMap<String, Vec<Symbol>> = Default::default();
|
||||
let mut names: FxIndexMap<String, Vec<Symbol>> = Default::default();
|
||||
let mut names_len = 0;
|
||||
|
||||
// Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and
|
||||
|
|
|
|||
|
|
@ -945,7 +945,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else {
|
||||
match (types, traits) {
|
||||
let mut types = types.to_vec();
|
||||
types.sort();
|
||||
let mut traits = traits.to_vec();
|
||||
traits.sort();
|
||||
match (&types[..], &traits[..]) {
|
||||
([], []) => {
|
||||
err.span_suggestion_verbose(
|
||||
span,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::astconv::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds};
|
||||
use crate::bounds::Bounds;
|
||||
use crate::errors::TraitObjectDeclaredWithNoTraits;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
|
|
@ -14,7 +14,6 @@ use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
|
|||
use rustc_trait_selection::traits::{self, astconv_object_safety_violations};
|
||||
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use super::AstConv;
|
||||
|
||||
|
|
@ -148,8 +147,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
}
|
||||
}
|
||||
|
||||
// Use a `BTreeSet` to keep output in a more consistent order.
|
||||
let mut associated_types: FxHashMap<Span, BTreeSet<DefId>> = FxHashMap::default();
|
||||
let mut associated_types: FxIndexMap<Span, FxIndexSet<DefId>> = FxIndexMap::default();
|
||||
|
||||
let regular_traits_refs_spans = trait_bounds
|
||||
.into_iter()
|
||||
|
|
|
|||
|
|
@ -225,25 +225,6 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
|
|||
],
|
||||
Ty::new_ptr(tcx, ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
|
||||
),
|
||||
sym::option_payload_ptr => {
|
||||
let option_def_id = tcx.require_lang_item(hir::LangItem::Option, None);
|
||||
let p0 = param(0);
|
||||
(
|
||||
1,
|
||||
vec![Ty::new_ptr(
|
||||
tcx,
|
||||
ty::TypeAndMut {
|
||||
ty: Ty::new_adt(
|
||||
tcx,
|
||||
tcx.adt_def(option_def_id),
|
||||
tcx.mk_args_from_iter([ty::GenericArg::from(p0)].into_iter()),
|
||||
),
|
||||
mutbl: hir::Mutability::Not,
|
||||
},
|
||||
)],
|
||||
Ty::new_ptr(tcx, ty::TypeAndMut { ty: p0, mutbl: hir::Mutability::Not }),
|
||||
)
|
||||
}
|
||||
sym::ptr_mask => (
|
||||
1,
|
||||
vec![
|
||||
|
|
|
|||
|
|
@ -440,7 +440,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
|
|||
second: format!(
|
||||
"{}::",
|
||||
// Replace the existing lifetimes with a new named lifetime.
|
||||
self.tcx.replace_late_bound_regions_uncached(
|
||||
self.tcx.instantiate_bound_regions_uncached(
|
||||
poly_trait_ref,
|
||||
|_| {
|
||||
ty::Region::new_early_param(self.tcx, ty::EarlyParamRegion {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use rustc_hir::{ForeignItem, ForeignItemKind};
|
|||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_infer::traits::{ObligationCause, WellFormedLoc};
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::{self, Region, TyCtxt, TypeFoldable, TypeFolder};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_trait_selection::traits::{self, ObligationCtxt};
|
||||
|
||||
|
|
@ -68,7 +68,13 @@ fn diagnostic_hir_wf_check<'tcx>(
|
|||
let infcx = self.tcx.infer_ctxt().build();
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
|
||||
let tcx_ty = self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx });
|
||||
let tcx_ty = self.icx.to_ty(ty);
|
||||
// This visitor can walk into binders, resulting in the `tcx_ty` to
|
||||
// potentially reference escaping bound variables. We simply erase
|
||||
// those here.
|
||||
let tcx_ty = self.tcx.fold_regions(tcx_ty, |r, _| {
|
||||
if r.is_bound() { self.tcx.lifetimes.re_erased } else { r }
|
||||
});
|
||||
let cause = traits::ObligationCause::new(
|
||||
ty.span,
|
||||
self.def_id,
|
||||
|
|
@ -178,25 +184,3 @@ fn diagnostic_hir_wf_check<'tcx>(
|
|||
}
|
||||
visitor.cause
|
||||
}
|
||||
|
||||
struct EraseAllBoundRegions<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
// Higher ranked regions are complicated.
|
||||
// To make matters worse, the HIR WF check can instantiate them
|
||||
// outside of a `Binder`, due to the way we (ab)use
|
||||
// `ItemCtxt::to_ty`. To make things simpler, we just erase all
|
||||
// of them, regardless of depth. At worse, this will give
|
||||
// us an inaccurate span for an error message, but cannot
|
||||
// lead to unsoundness (we call `delay_span_bug` at the start
|
||||
// of `diagnostic_hir_wf_check`).
|
||||
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EraseAllBoundRegions<'tcx> {
|
||||
fn interner(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
|
||||
// FIXME(@lcnr): only erase escaping bound regions!
|
||||
if r.is_bound() { self.tcx.lifetimes.re_erased } else { r }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,6 +80,10 @@ pub(crate) fn insert_outlives_predicate<'tcx>(
|
|||
.or_insert(span);
|
||||
}
|
||||
|
||||
Component::Placeholder(_) => {
|
||||
span_bug!(span, "Should not deduce placeholder outlives component");
|
||||
}
|
||||
|
||||
Component::Alias(alias_ty) => {
|
||||
// This would either arise from something like:
|
||||
//
|
||||
|
|
|
|||
|
|
@ -625,6 +625,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = callee_expr.kind
|
||||
&& let Res::Local(_) = path.res
|
||||
&& let [segment] = &path.segments[..]
|
||||
{
|
||||
for id in self.tcx.hir().items() {
|
||||
if let Some(node) = self.tcx.hir().get_if_local(id.owner_id.into())
|
||||
&& let hir::Node::Item(item) = node
|
||||
&& let hir::ItemKind::Fn(..) = item.kind
|
||||
&& item.ident.name == segment.ident.name
|
||||
{
|
||||
err.span_label(
|
||||
self.tcx.def_span(id.owner_id),
|
||||
"this function of the same name is available here, but it's shadowed by \
|
||||
the local binding",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut inner_callee_path = None;
|
||||
let def = match callee_expr.kind {
|
||||
hir::ExprKind::Path(ref qpath) => {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
self.annotate_alternative_method_deref(err, expr, error);
|
||||
self.explain_self_literal(err, expr, expected, expr_ty);
|
||||
|
||||
// Use `||` to give these suggestions a precedence
|
||||
let suggested = self.suggest_missing_parentheses(err, expr)
|
||||
|
|
@ -1027,6 +1028,59 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
return false;
|
||||
}
|
||||
|
||||
fn explain_self_literal(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
expr: &hir::Expr<'tcx>,
|
||||
expected: Ty<'tcx>,
|
||||
found: Ty<'tcx>,
|
||||
) {
|
||||
match expr.peel_drop_temps().kind {
|
||||
hir::ExprKind::Struct(
|
||||
hir::QPath::Resolved(
|
||||
None,
|
||||
hir::Path { res: hir::def::Res::SelfTyAlias { alias_to, .. }, span, .. },
|
||||
),
|
||||
..,
|
||||
)
|
||||
| hir::ExprKind::Call(
|
||||
hir::Expr {
|
||||
kind:
|
||||
hir::ExprKind::Path(hir::QPath::Resolved(
|
||||
None,
|
||||
hir::Path {
|
||||
res: hir::def::Res::SelfTyAlias { alias_to, .. },
|
||||
span,
|
||||
..
|
||||
},
|
||||
)),
|
||||
..
|
||||
},
|
||||
..,
|
||||
) => {
|
||||
if let Some(hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Impl(hir::Impl { self_ty, .. }),
|
||||
..
|
||||
})) = self.tcx.hir().get_if_local(*alias_to)
|
||||
{
|
||||
err.span_label(self_ty.span, "this is the type of the `Self` literal");
|
||||
}
|
||||
if let ty::Adt(e_def, e_args) = expected.kind()
|
||||
&& let ty::Adt(f_def, _f_args) = found.kind()
|
||||
&& e_def == f_def
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
*span,
|
||||
"use the type name directly",
|
||||
self.tcx.value_path_str_with_args(*alias_to, e_args),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn note_wrong_return_ty_due_to_generic_arg(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
|
|
|
|||
|
|
@ -626,15 +626,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
let coerce_to = match opt_coerce_to {
|
||||
Some(c) => c,
|
||||
None => {
|
||||
// If the loop context is not a `loop { }`, then break with
|
||||
// a value is illegal, and `opt_coerce_to` will be `None`.
|
||||
// Return error in that case (#114529).
|
||||
return Ty::new_misc_error(tcx);
|
||||
}
|
||||
};
|
||||
// If the loop context is not a `loop { }`, then break with
|
||||
// a value is illegal, and `opt_coerce_to` will be `None`.
|
||||
// Set expectation to error in that case and set tainted
|
||||
// by error (#114529)
|
||||
let coerce_to = opt_coerce_to.unwrap_or_else(|| {
|
||||
let guar = tcx.sess.delay_span_bug(
|
||||
expr.span,
|
||||
"illegal break with value found but no error reported",
|
||||
);
|
||||
self.set_tainted_by_errors(guar);
|
||||
Ty::new_error(tcx, guar)
|
||||
});
|
||||
|
||||
// Recurse without `enclosing_breakables` borrowed.
|
||||
e_ty = self.check_expr_with_hint(e, coerce_to);
|
||||
|
|
@ -1897,7 +1900,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
.collect();
|
||||
|
||||
if !private_fields.is_empty() {
|
||||
self.report_private_fields(adt_ty, span, private_fields, ast_fields);
|
||||
self.report_private_fields(adt_ty, span, expr.span, private_fields, ast_fields);
|
||||
} else {
|
||||
self.report_missing_fields(
|
||||
adt_ty,
|
||||
|
|
@ -2056,6 +2059,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
&self,
|
||||
adt_ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
expr_span: Span,
|
||||
private_fields: Vec<&ty::FieldDef>,
|
||||
used_fields: &'tcx [hir::ExprField<'tcx>],
|
||||
) {
|
||||
|
|
@ -2100,6 +2104,81 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
were = pluralize!("was", remaining_private_fields_len),
|
||||
));
|
||||
}
|
||||
|
||||
if let ty::Adt(def, _) = adt_ty.kind() {
|
||||
let def_id = def.did();
|
||||
let mut items = self
|
||||
.tcx
|
||||
.inherent_impls(def_id)
|
||||
.iter()
|
||||
.flat_map(|i| self.tcx.associated_items(i).in_definition_order())
|
||||
// Only assoc fn with no receivers.
|
||||
.filter(|item| {
|
||||
matches!(item.kind, ty::AssocKind::Fn) && !item.fn_has_self_parameter
|
||||
})
|
||||
.filter_map(|item| {
|
||||
// Only assoc fns that return `Self`
|
||||
let fn_sig = self.tcx.fn_sig(item.def_id).skip_binder();
|
||||
let ret_ty = fn_sig.output();
|
||||
let ret_ty =
|
||||
self.tcx.normalize_erasing_late_bound_regions(self.param_env, ret_ty);
|
||||
if !self.can_eq(self.param_env, ret_ty, adt_ty) {
|
||||
return None;
|
||||
}
|
||||
let input_len = fn_sig.inputs().skip_binder().len();
|
||||
let order = !item.name.as_str().starts_with("new");
|
||||
Some((order, item.name, input_len))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
items.sort_by_key(|(order, _, _)| *order);
|
||||
let suggestion = |name, args| {
|
||||
format!(
|
||||
"::{name}({})",
|
||||
std::iter::repeat("_").take(args).collect::<Vec<_>>().join(", ")
|
||||
)
|
||||
};
|
||||
match &items[..] {
|
||||
[] => {}
|
||||
[(_, name, args)] => {
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_hi().with_hi(expr_span.hi()),
|
||||
format!("you might have meant to use the `{name}` associated function"),
|
||||
suggestion(name, *args),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
err.span_suggestions(
|
||||
span.shrink_to_hi().with_hi(expr_span.hi()),
|
||||
"you might have meant to use an associated function to build this type",
|
||||
items
|
||||
.iter()
|
||||
.map(|(_, name, args)| suggestion(name, *args))
|
||||
.collect::<Vec<String>>(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
if let Some(default_trait) = self.tcx.get_diagnostic_item(sym::Default)
|
||||
&& self
|
||||
.infcx
|
||||
.type_implements_trait(default_trait, [adt_ty], self.param_env)
|
||||
.may_apply()
|
||||
{
|
||||
err.multipart_suggestion(
|
||||
"consider using the `Default` trait",
|
||||
vec![
|
||||
(span.shrink_to_lo(), "<".to_string()),
|
||||
(
|
||||
span.shrink_to_hi().with_hi(expr_span.hi()),
|
||||
" as std::default::Default>::default()".to_string(),
|
||||
),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
err.emit();
|
||||
}
|
||||
|
||||
|
|
@ -2191,7 +2270,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
if let Some(field_name) =
|
||||
find_best_match_for_name(&available_field_names, field.ident.name, None)
|
||||
{
|
||||
err.span_suggestion(
|
||||
err.span_label(field.ident.span, "unknown field");
|
||||
err.span_suggestion_verbose(
|
||||
field.ident.span,
|
||||
"a field with a similar name exists",
|
||||
field_name,
|
||||
|
|
@ -2420,35 +2500,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
ty: Ty<'tcx>,
|
||||
) {
|
||||
let Some(output_ty) = self.get_impl_future_output_ty(ty) else {
|
||||
err.span_label(field_ident.span, "unknown field");
|
||||
return;
|
||||
};
|
||||
let mut add_label = true;
|
||||
if let ty::Adt(def, _) = output_ty.kind() {
|
||||
// no field access on enum type
|
||||
if !def.is_enum() {
|
||||
if def
|
||||
.non_enum_variant()
|
||||
.fields
|
||||
.iter()
|
||||
.any(|field| field.ident(self.tcx) == field_ident)
|
||||
{
|
||||
add_label = false;
|
||||
err.span_label(
|
||||
field_ident.span,
|
||||
"field not available in `impl Future`, but it is available in its `Output`",
|
||||
);
|
||||
err.span_suggestion_verbose(
|
||||
base.span.shrink_to_hi(),
|
||||
"consider `await`ing on the `Future` and access the field of its `Output`",
|
||||
".await",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
let ty::Adt(def, _) = output_ty.kind() else {
|
||||
err.span_label(field_ident.span, "unknown field");
|
||||
return;
|
||||
};
|
||||
// no field access on enum type
|
||||
if def.is_enum() {
|
||||
err.span_label(field_ident.span, "unknown field");
|
||||
return;
|
||||
}
|
||||
if add_label {
|
||||
err.span_label(field_ident.span, format!("field not found in `{ty}`"));
|
||||
if !def.non_enum_variant().fields.iter().any(|field| field.ident(self.tcx) == field_ident) {
|
||||
err.span_label(field_ident.span, "unknown field");
|
||||
return;
|
||||
}
|
||||
err.span_label(
|
||||
field_ident.span,
|
||||
"field not available in `impl Future`, but it is available in its `Output`",
|
||||
);
|
||||
err.span_suggestion_verbose(
|
||||
base.span.shrink_to_hi(),
|
||||
"consider `await`ing on the `Future` and access the field of its `Output`",
|
||||
".await",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
||||
fn ban_nonexisting_field(
|
||||
|
|
@ -2471,16 +2548,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
ty::RawPtr(..) => {
|
||||
self.suggest_first_deref_field(&mut err, expr, base, ident);
|
||||
}
|
||||
ty::Adt(def, _) if !def.is_enum() => {
|
||||
self.suggest_fields_on_recordish(&mut err, expr, def, ident);
|
||||
}
|
||||
ty::Param(param_ty) => {
|
||||
err.span_label(ident.span, "unknown field");
|
||||
self.point_at_param_definition(&mut err, param_ty);
|
||||
}
|
||||
ty::Alias(ty::Opaque, _) => {
|
||||
self.suggest_await_on_field_access(&mut err, ident, base, base_ty.peel_refs());
|
||||
}
|
||||
_ => {}
|
||||
_ => {
|
||||
err.span_label(ident.span, "unknown field");
|
||||
}
|
||||
}
|
||||
|
||||
self.suggest_fn_call(&mut err, base, base_ty, |output_ty| {
|
||||
|
|
@ -2633,34 +2710,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
err.span_label(param_span, format!("type parameter '{param_name}' declared here"));
|
||||
}
|
||||
|
||||
fn suggest_fields_on_recordish(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
expr: &hir::Expr<'_>,
|
||||
def: ty::AdtDef<'tcx>,
|
||||
field: Ident,
|
||||
) {
|
||||
let available_field_names = self.available_field_names(def.non_enum_variant(), expr, &[]);
|
||||
if let Some(suggested_field_name) =
|
||||
find_best_match_for_name(&available_field_names, field.name, None)
|
||||
{
|
||||
err.span_suggestion(
|
||||
field.span,
|
||||
"a field with a similar name exists",
|
||||
suggested_field_name,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
err.span_label(field.span, "unknown field");
|
||||
if !available_field_names.is_empty() {
|
||||
err.note(format!(
|
||||
"available fields are: {}",
|
||||
self.name_series_display(available_field_names),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn maybe_suggest_array_indexing(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
|
|
@ -2669,6 +2718,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
field: Ident,
|
||||
len: ty::Const<'tcx>,
|
||||
) {
|
||||
err.span_label(field.span, "unknown field");
|
||||
if let (Some(len), Ok(user_index)) =
|
||||
(len.try_eval_target_usize(self.tcx, self.param_env), field.as_str().parse::<u64>())
|
||||
&& let Ok(base) = self.tcx.sess.source_map().span_to_snippet(base.span)
|
||||
|
|
@ -2691,6 +2741,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
base: &hir::Expr<'_>,
|
||||
field: Ident,
|
||||
) {
|
||||
err.span_label(field.span, "unknown field");
|
||||
if let Ok(base) = self.tcx.sess.source_map().span_to_snippet(base.span) {
|
||||
let msg = format!("`{base}` is a raw pointer; try dereferencing it");
|
||||
let suggestion = format!("(*{base}).{field}");
|
||||
|
|
@ -2709,7 +2760,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
let mut err = type_error_struct!(
|
||||
self.tcx().sess,
|
||||
field.span,
|
||||
span,
|
||||
expr_t,
|
||||
E0609,
|
||||
"no field `{field}` on type `{expr_t}`",
|
||||
|
|
@ -2717,10 +2768,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
// try to add a suggestion in case the field is a nested field of a field of the Adt
|
||||
let mod_id = self.tcx.parent_module(id).to_def_id();
|
||||
if let Some((fields, args)) =
|
||||
self.get_field_candidates_considering_privacy(span, expr_t, mod_id)
|
||||
let (ty, unwrap) = if let ty::Adt(def, args) = expr_t.kind()
|
||||
&& (self.tcx.is_diagnostic_item(sym::Result, def.did())
|
||||
|| self.tcx.is_diagnostic_item(sym::Option, def.did()))
|
||||
&& let Some(arg) = args.get(0)
|
||||
&& let Some(ty) = arg.as_type()
|
||||
{
|
||||
let candidate_fields: Vec<_> = fields
|
||||
(ty, "unwrap().")
|
||||
} else {
|
||||
(expr_t, "")
|
||||
};
|
||||
for (found_fields, args) in
|
||||
self.get_field_candidates_considering_privacy(span, ty, mod_id, id)
|
||||
{
|
||||
let field_names = found_fields.iter().map(|field| field.name).collect::<Vec<_>>();
|
||||
let mut candidate_fields: Vec<_> = found_fields
|
||||
.into_iter()
|
||||
.filter_map(|candidate_field| {
|
||||
self.check_for_nested_field_satisfying(
|
||||
span,
|
||||
|
|
@ -2729,17 +2792,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
args,
|
||||
vec![],
|
||||
mod_id,
|
||||
id,
|
||||
)
|
||||
})
|
||||
.map(|mut field_path| {
|
||||
field_path.pop();
|
||||
field_path
|
||||
.iter()
|
||||
.map(|id| id.name.to_ident_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(".")
|
||||
.map(|id| format!("{}.", id.name.to_ident_string()))
|
||||
.collect::<String>()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
candidate_fields.sort();
|
||||
|
||||
let len = candidate_fields.len();
|
||||
if len > 0 {
|
||||
|
|
@ -2750,9 +2814,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
if len > 1 { "some" } else { "one" },
|
||||
if len > 1 { "have" } else { "has" },
|
||||
),
|
||||
candidate_fields.iter().map(|path| format!("{path}.")),
|
||||
candidate_fields.iter().map(|path| format!("{unwrap}{path}")),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
if let Some(field_name) = find_best_match_for_name(&field_names, field.name, None) {
|
||||
err.span_suggestion_verbose(
|
||||
field.span,
|
||||
"a field with a similar name exists",
|
||||
format!("{unwrap}{}", field_name),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else if !field_names.is_empty() {
|
||||
let is = if field_names.len() == 1 { " is" } else { "s are" };
|
||||
err.note(format!(
|
||||
"available field{is}: {}",
|
||||
self.name_series_display(field_names),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
err
|
||||
|
|
@ -2781,33 +2860,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
span: Span,
|
||||
base_ty: Ty<'tcx>,
|
||||
mod_id: DefId,
|
||||
) -> Option<(impl Iterator<Item = &'tcx ty::FieldDef> + 'tcx, GenericArgsRef<'tcx>)> {
|
||||
hir_id: hir::HirId,
|
||||
) -> Vec<(Vec<&'tcx ty::FieldDef>, GenericArgsRef<'tcx>)> {
|
||||
debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_ty);
|
||||
|
||||
for (base_t, _) in self.autoderef(span, base_ty) {
|
||||
match base_t.kind() {
|
||||
ty::Adt(base_def, args) if !base_def.is_enum() => {
|
||||
let tcx = self.tcx;
|
||||
let fields = &base_def.non_enum_variant().fields;
|
||||
// Some struct, e.g. some that impl `Deref`, have all private fields
|
||||
// because you're expected to deref them to access the _real_ fields.
|
||||
// This, for example, will help us suggest accessing a field through a `Box<T>`.
|
||||
if fields.iter().all(|field| !field.vis.is_accessible_from(mod_id, tcx)) {
|
||||
continue;
|
||||
self.autoderef(span, base_ty)
|
||||
.filter_map(move |(base_t, _)| {
|
||||
match base_t.kind() {
|
||||
ty::Adt(base_def, args) if !base_def.is_enum() => {
|
||||
let tcx = self.tcx;
|
||||
let fields = &base_def.non_enum_variant().fields;
|
||||
// Some struct, e.g. some that impl `Deref`, have all private fields
|
||||
// because you're expected to deref them to access the _real_ fields.
|
||||
// This, for example, will help us suggest accessing a field through a `Box<T>`.
|
||||
if fields.iter().all(|field| !field.vis.is_accessible_from(mod_id, tcx)) {
|
||||
return None;
|
||||
}
|
||||
return Some((
|
||||
fields
|
||||
.iter()
|
||||
.filter(move |field| {
|
||||
field.vis.is_accessible_from(mod_id, tcx)
|
||||
&& self.is_field_suggestable(field, hir_id, span)
|
||||
})
|
||||
// For compile-time reasons put a limit on number of fields we search
|
||||
.take(100)
|
||||
.collect::<Vec<_>>(),
|
||||
*args,
|
||||
));
|
||||
}
|
||||
return Some((
|
||||
fields
|
||||
.iter()
|
||||
.filter(move |field| field.vis.is_accessible_from(mod_id, tcx))
|
||||
// For compile-time reasons put a limit on number of fields we search
|
||||
.take(100),
|
||||
args,
|
||||
));
|
||||
_ => None,
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// This method is called after we have encountered a missing field error to recursively
|
||||
|
|
@ -2820,6 +2905,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
subst: GenericArgsRef<'tcx>,
|
||||
mut field_path: Vec<Ident>,
|
||||
mod_id: DefId,
|
||||
hir_id: HirId,
|
||||
) -> Option<Vec<Ident>> {
|
||||
debug!(
|
||||
"check_for_nested_field_satisfying(span: {:?}, candidate_field: {:?}, field_path: {:?}",
|
||||
|
|
@ -2835,20 +2921,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let field_ty = candidate_field.ty(self.tcx, subst);
|
||||
if matches(candidate_field, field_ty) {
|
||||
return Some(field_path);
|
||||
} else if let Some((nested_fields, subst)) =
|
||||
self.get_field_candidates_considering_privacy(span, field_ty, mod_id)
|
||||
{
|
||||
// recursively search fields of `candidate_field` if it's a ty::Adt
|
||||
for field in nested_fields {
|
||||
if let Some(field_path) = self.check_for_nested_field_satisfying(
|
||||
span,
|
||||
matches,
|
||||
field,
|
||||
subst,
|
||||
field_path.clone(),
|
||||
mod_id,
|
||||
) {
|
||||
return Some(field_path);
|
||||
} else {
|
||||
for (nested_fields, subst) in
|
||||
self.get_field_candidates_considering_privacy(span, field_ty, mod_id, hir_id)
|
||||
{
|
||||
// recursively search fields of `candidate_field` if it's a ty::Adt
|
||||
for field in nested_fields {
|
||||
if let Some(field_path) = self.check_for_nested_field_satisfying(
|
||||
span,
|
||||
matches,
|
||||
field,
|
||||
subst,
|
||||
field_path.clone(),
|
||||
mod_id,
|
||||
hir_id,
|
||||
) {
|
||||
return Some(field_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -846,7 +846,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let bound_vars = self.tcx.late_bound_vars(hir_ty.hir_id.owner.into());
|
||||
let ty = Binder::bind_with_vars(ty, bound_vars);
|
||||
let ty = self.normalize(hir_ty.span, ty);
|
||||
let ty = self.tcx.erase_late_bound_regions(ty);
|
||||
let ty = self.tcx.instantiate_bound_regions_with_erased(ty);
|
||||
if self.can_coerce(expected, ty) {
|
||||
err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other {
|
||||
span: hir_ty.span,
|
||||
|
|
@ -1023,7 +1023,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
if let hir::FnRetTy::Return(ty) = fn_decl.output {
|
||||
let ty = self.astconv().ast_ty_to_ty(ty);
|
||||
let bound_vars = self.tcx.late_bound_vars(fn_id);
|
||||
let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars));
|
||||
let ty = self
|
||||
.tcx
|
||||
.instantiate_bound_regions_with_erased(Binder::bind_with_vars(ty, bound_vars));
|
||||
let ty = match self.tcx.asyncness(fn_id.owner) {
|
||||
ty::Asyncness::Yes => self.get_impl_future_output_ty(ty).unwrap_or_else(|| {
|
||||
span_bug!(fn_decl.output.span(), "failed to get output type of async function")
|
||||
|
|
|
|||
|
|
@ -809,7 +809,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
let new_trait_ref = this.erase_late_bound_regions(new_trait_ref);
|
||||
let new_trait_ref = this.instantiate_bound_regions_with_erased(new_trait_ref);
|
||||
|
||||
let (xform_self_ty, xform_ret_ty) =
|
||||
this.xform_self_ty(item, new_trait_ref.self_ty(), new_trait_ref.args);
|
||||
|
|
@ -1885,7 +1885,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
fn_sig.instantiate(self.tcx, args)
|
||||
};
|
||||
|
||||
self.erase_late_bound_regions(xform_fn_sig)
|
||||
self.instantiate_bound_regions_with_erased(xform_fn_sig)
|
||||
}
|
||||
|
||||
/// Gets the type of an impl and generate substitutions with inference vars.
|
||||
|
|
@ -1897,7 +1897,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
/// Replaces late-bound-regions bound by `value` with `'static` using
|
||||
/// `ty::erase_late_bound_regions`.
|
||||
/// `ty::instantiate_bound_regions_with_erased`.
|
||||
///
|
||||
/// This is only a reasonable thing to do during the *probe* phase, not the *confirm* phase, of
|
||||
/// method matching. It is reasonable during the probe phase because we don't consider region
|
||||
|
|
@ -1914,11 +1914,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
/// region got replaced with the same variable, which requires a bit more coordination
|
||||
/// and/or tracking the substitution and
|
||||
/// so forth.
|
||||
fn erase_late_bound_regions<T>(&self, value: ty::Binder<'tcx, T>) -> T
|
||||
fn instantiate_bound_regions_with_erased<T>(&self, value: ty::Binder<'tcx, T>) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
self.tcx.erase_late_bound_regions(value)
|
||||
self.tcx.instantiate_bound_regions_with_erased(value)
|
||||
}
|
||||
|
||||
/// Determine if the given associated item type is relevant in the current context.
|
||||
|
|
|
|||
|
|
@ -1426,6 +1426,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
if !suggs.is_empty()
|
||||
&& let Some(span) = sugg_span
|
||||
{
|
||||
suggs.sort();
|
||||
err.span_suggestions(
|
||||
span.with_hi(item_name.span.lo()),
|
||||
"use fully-qualified syntax to disambiguate",
|
||||
|
|
@ -1454,7 +1455,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
.filter_map(|item| {
|
||||
// Only assoc fns that return `Self`, `Option<Self>` or `Result<Self, _>`.
|
||||
let ret_ty = self.tcx.fn_sig(item.def_id).skip_binder().output();
|
||||
let ret_ty = self.tcx.erase_late_bound_regions(ret_ty);
|
||||
let ret_ty = self.tcx.instantiate_bound_regions_with_erased(ret_ty);
|
||||
let ty::Adt(def, args) = ret_ty.kind() else {
|
||||
return None;
|
||||
};
|
||||
|
|
@ -1983,69 +1984,73 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
item_name: Ident,
|
||||
return_type: Option<Ty<'tcx>>,
|
||||
) {
|
||||
if let SelfSource::MethodCall(expr) = source
|
||||
&& let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id()
|
||||
&& let Some((fields, args)) =
|
||||
self.get_field_candidates_considering_privacy(span, actual, mod_id)
|
||||
{
|
||||
let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id));
|
||||
if let SelfSource::MethodCall(expr) = source {
|
||||
let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id();
|
||||
for (fields, args) in
|
||||
self.get_field_candidates_considering_privacy(span, actual, mod_id, expr.hir_id)
|
||||
{
|
||||
let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id));
|
||||
|
||||
let lang_items = self.tcx.lang_items();
|
||||
let never_mention_traits = [
|
||||
lang_items.clone_trait(),
|
||||
lang_items.deref_trait(),
|
||||
lang_items.deref_mut_trait(),
|
||||
self.tcx.get_diagnostic_item(sym::AsRef),
|
||||
self.tcx.get_diagnostic_item(sym::AsMut),
|
||||
self.tcx.get_diagnostic_item(sym::Borrow),
|
||||
self.tcx.get_diagnostic_item(sym::BorrowMut),
|
||||
];
|
||||
let candidate_fields: Vec<_> = fields
|
||||
.filter_map(|candidate_field| {
|
||||
self.check_for_nested_field_satisfying(
|
||||
span,
|
||||
&|_, field_ty| {
|
||||
self.lookup_probe_for_diagnostic(
|
||||
item_name,
|
||||
field_ty,
|
||||
call_expr,
|
||||
ProbeScope::TraitsInScope,
|
||||
return_type,
|
||||
)
|
||||
.is_ok_and(|pick| {
|
||||
!never_mention_traits
|
||||
.iter()
|
||||
.flatten()
|
||||
.any(|def_id| self.tcx.parent(pick.item.def_id) == *def_id)
|
||||
})
|
||||
},
|
||||
candidate_field,
|
||||
args,
|
||||
vec![],
|
||||
mod_id,
|
||||
)
|
||||
})
|
||||
.map(|field_path| {
|
||||
field_path
|
||||
.iter()
|
||||
.map(|id| id.name.to_ident_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(".")
|
||||
})
|
||||
.collect();
|
||||
let lang_items = self.tcx.lang_items();
|
||||
let never_mention_traits = [
|
||||
lang_items.clone_trait(),
|
||||
lang_items.deref_trait(),
|
||||
lang_items.deref_mut_trait(),
|
||||
self.tcx.get_diagnostic_item(sym::AsRef),
|
||||
self.tcx.get_diagnostic_item(sym::AsMut),
|
||||
self.tcx.get_diagnostic_item(sym::Borrow),
|
||||
self.tcx.get_diagnostic_item(sym::BorrowMut),
|
||||
];
|
||||
let mut candidate_fields: Vec<_> = fields
|
||||
.into_iter()
|
||||
.filter_map(|candidate_field| {
|
||||
self.check_for_nested_field_satisfying(
|
||||
span,
|
||||
&|_, field_ty| {
|
||||
self.lookup_probe_for_diagnostic(
|
||||
item_name,
|
||||
field_ty,
|
||||
call_expr,
|
||||
ProbeScope::TraitsInScope,
|
||||
return_type,
|
||||
)
|
||||
.is_ok_and(|pick| {
|
||||
!never_mention_traits
|
||||
.iter()
|
||||
.flatten()
|
||||
.any(|def_id| self.tcx.parent(pick.item.def_id) == *def_id)
|
||||
})
|
||||
},
|
||||
candidate_field,
|
||||
args,
|
||||
vec![],
|
||||
mod_id,
|
||||
expr.hir_id,
|
||||
)
|
||||
})
|
||||
.map(|field_path| {
|
||||
field_path
|
||||
.iter()
|
||||
.map(|id| id.name.to_ident_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(".")
|
||||
})
|
||||
.collect();
|
||||
candidate_fields.sort();
|
||||
|
||||
let len = candidate_fields.len();
|
||||
if len > 0 {
|
||||
err.span_suggestions(
|
||||
item_name.span.shrink_to_lo(),
|
||||
format!(
|
||||
"{} of the expressions' fields {} a method of the same name",
|
||||
if len > 1 { "some" } else { "one" },
|
||||
if len > 1 { "have" } else { "has" },
|
||||
),
|
||||
candidate_fields.iter().map(|path| format!("{path}.")),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
let len = candidate_fields.len();
|
||||
if len > 0 {
|
||||
err.span_suggestions(
|
||||
item_name.span.shrink_to_lo(),
|
||||
format!(
|
||||
"{} of the expressions' fields {} a method of the same name",
|
||||
if len > 1 { "some" } else { "one" },
|
||||
if len > 1 { "have" } else { "has" },
|
||||
),
|
||||
candidate_fields.iter().map(|path| format!("{path}.")),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2564,13 +2569,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.tcx.item_name(*trait_did),
|
||||
)
|
||||
});
|
||||
let mut sugg: Vec<_> = path_strings.chain(glob_path_strings).collect();
|
||||
sugg.sort();
|
||||
|
||||
err.span_suggestions(
|
||||
span,
|
||||
msg,
|
||||
path_strings.chain(glob_path_strings),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
err.span_suggestions(span, msg, sugg, Applicability::MaybeIncorrect);
|
||||
}
|
||||
|
||||
fn suggest_valid_traits(
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use rustc_hir as hir;
|
|||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
|
||||
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
|
||||
use rustc_middle::ty::visit::TypeVisitableExt;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_span::symbol::sym;
|
||||
|
|
@ -768,41 +768,22 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
struct EraseEarlyRegions<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EraseEarlyRegions<'tcx> {
|
||||
fn interner(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
if ty.has_type_flags(ty::TypeFlags::HAS_FREE_REGIONS) {
|
||||
ty.super_fold_with(self)
|
||||
} else {
|
||||
ty
|
||||
}
|
||||
}
|
||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
if r.is_bound() { r } else { self.tcx.lifetimes.re_erased }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> {
|
||||
fn interner(&self) -> TyCtxt<'tcx> {
|
||||
self.fcx.tcx
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||
let tcx = self.fcx.tcx;
|
||||
match self.fcx.fully_resolve(t) {
|
||||
Ok(t) if self.fcx.next_trait_solver() => {
|
||||
// We must normalize erasing regions here, since later lints
|
||||
// expect that types that show up in the typeck are fully
|
||||
// normalized.
|
||||
if let Ok(t) = self.fcx.tcx.try_normalize_erasing_regions(self.fcx.param_env, t) {
|
||||
if let Ok(t) = tcx.try_normalize_erasing_regions(self.fcx.param_env, t) {
|
||||
t
|
||||
} else {
|
||||
EraseEarlyRegions { tcx: self.fcx.tcx }.fold_ty(t)
|
||||
tcx.fold_regions(t, |_, _| tcx.lifetimes.re_erased)
|
||||
}
|
||||
}
|
||||
Ok(t) => {
|
||||
|
|
@ -810,7 +791,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> {
|
|||
// (e.g. keep `for<'a>` named `for<'a>`).
|
||||
// This allows NLL to generate error messages that
|
||||
// refer to the higher-ranked lifetime names written by the user.
|
||||
EraseEarlyRegions { tcx: self.fcx.tcx }.fold_ty(t)
|
||||
tcx.fold_regions(t, |_, _| tcx.lifetimes.re_erased)
|
||||
}
|
||||
Err(_) => {
|
||||
debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ edition = "2021"
|
|||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
arrayvec = { version = "0.7", default-features = false }
|
||||
rustc_index_macros = { path = "../rustc_index_macros", default-features = false }
|
||||
rustc_macros = { path = "../rustc_macros", optional = true }
|
||||
rustc_serialize = { path = "../rustc_serialize", optional = true }
|
||||
smallvec = "1.8.1"
|
||||
|
|
@ -14,5 +15,5 @@ smallvec = "1.8.1"
|
|||
[features]
|
||||
# tidy-alphabetical-start
|
||||
default = ["nightly"]
|
||||
nightly = ["rustc_serialize", "rustc_macros"]
|
||||
nightly = ["rustc_serialize", "rustc_macros", "rustc_index_macros/nightly"]
|
||||
# tidy-alphabetical-end
|
||||
|
|
|
|||
|
|
@ -25,8 +25,7 @@ mod vec;
|
|||
|
||||
pub use {idx::Idx, slice::IndexSlice, vec::IndexVec};
|
||||
|
||||
#[cfg(feature = "rustc_macros")]
|
||||
pub use rustc_macros::newtype_index;
|
||||
pub use rustc_index_macros::newtype_index;
|
||||
|
||||
/// Type size assertion. The first argument is a type and the second argument is its expected size.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Allows the macro invocation below to work
|
||||
use crate as rustc_index;
|
||||
|
||||
rustc_macros::newtype_index! {
|
||||
crate::newtype_index! {
|
||||
#[max = 0xFFFF_FFFA]
|
||||
struct MyIdx {}
|
||||
}
|
||||
|
|
|
|||
17
compiler/rustc_index_macros/Cargo.toml
Normal file
17
compiler/rustc_index_macros/Cargo.toml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
[package]
|
||||
name = "rustc_index_macros"
|
||||
version = "0.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
synstructure = "0.13.0"
|
||||
syn = { version = "2.0.9", features = ["full"] }
|
||||
proc-macro2 = "1"
|
||||
quote = "1"
|
||||
|
||||
[features]
|
||||
default = ["nightly"]
|
||||
nightly = []
|
||||
30
compiler/rustc_index_macros/src/lib.rs
Normal file
30
compiler/rustc_index_macros/src/lib.rs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#![cfg_attr(feature = "nightly", feature(allow_internal_unstable))]
|
||||
#![cfg_attr(feature = "nightly", allow(internal_features))]
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
mod newtype;
|
||||
|
||||
/// Creates a struct type `S` that can be used as an index with
|
||||
/// `IndexVec` and so on.
|
||||
///
|
||||
/// There are two ways of interacting with these indices:
|
||||
///
|
||||
/// - The `From` impls are the preferred way. So you can do
|
||||
/// `S::from(v)` with a `usize` or `u32`. And you can convert back
|
||||
/// to an integer with `u32::from(s)`.
|
||||
///
|
||||
/// - Alternatively, you can use the methods `S::new(v)` and `s.index()`
|
||||
/// to create/return a value.
|
||||
///
|
||||
/// Internally, the index uses a u32, so the index must not exceed
|
||||
/// `u32::MAX`. You can also customize things like the `Debug` impl,
|
||||
/// what traits are derived, and so forth via the macro.
|
||||
#[proc_macro]
|
||||
#[cfg_attr(
|
||||
feature = "nightly",
|
||||
allow_internal_unstable(step_trait, rustc_attrs, trusted_step, spec_option_partial_eq)
|
||||
)]
|
||||
pub fn newtype_index(input: TokenStream) -> TokenStream {
|
||||
newtype::newtype(input)
|
||||
}
|
||||
|
|
@ -24,9 +24,16 @@ impl Parse for Newtype {
|
|||
let mut consts = Vec::new();
|
||||
let mut encodable = true;
|
||||
let mut ord = true;
|
||||
let mut gate_rustc_only = quote! {};
|
||||
let mut gate_rustc_only_cfg = quote! { all() };
|
||||
|
||||
attrs.retain(|attr| match attr.path().get_ident() {
|
||||
Some(ident) => match &*ident.to_string() {
|
||||
"gate_rustc_only" => {
|
||||
gate_rustc_only = quote! { #[cfg(feature = "nightly")] };
|
||||
gate_rustc_only_cfg = quote! { feature = "nightly" };
|
||||
false
|
||||
}
|
||||
"custom_encodable" => {
|
||||
encodable = false;
|
||||
false
|
||||
|
|
@ -88,11 +95,13 @@ impl Parse for Newtype {
|
|||
|
||||
let encodable_impls = if encodable {
|
||||
quote! {
|
||||
#gate_rustc_only
|
||||
impl<D: ::rustc_serialize::Decoder> ::rustc_serialize::Decodable<D> for #name {
|
||||
fn decode(d: &mut D) -> Self {
|
||||
Self::from_u32(d.read_u32())
|
||||
}
|
||||
}
|
||||
#gate_rustc_only
|
||||
impl<E: ::rustc_serialize::Encoder> ::rustc_serialize::Encodable<E> for #name {
|
||||
fn encode(&self, e: &mut E) {
|
||||
e.emit_u32(self.private);
|
||||
|
|
@ -110,6 +119,7 @@ impl Parse for Newtype {
|
|||
|
||||
let step = if ord {
|
||||
quote! {
|
||||
#gate_rustc_only
|
||||
impl ::std::iter::Step for #name {
|
||||
#[inline]
|
||||
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
|
||||
|
|
@ -131,6 +141,7 @@ impl Parse for Newtype {
|
|||
}
|
||||
|
||||
// Safety: The implementation of `Step` upholds all invariants.
|
||||
#gate_rustc_only
|
||||
unsafe impl ::std::iter::TrustedStep for #name {}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -148,6 +159,7 @@ impl Parse for Newtype {
|
|||
let spec_partial_eq_impl = if let Lit::Int(max) = &max {
|
||||
if let Ok(max_val) = max.base10_parse::<u32>() {
|
||||
quote! {
|
||||
#gate_rustc_only
|
||||
impl core::option::SpecOptionPartialEq for #name {
|
||||
#[inline]
|
||||
fn eq(l: &Option<Self>, r: &Option<Self>) -> bool {
|
||||
|
|
@ -173,8 +185,8 @@ impl Parse for Newtype {
|
|||
Ok(Self(quote! {
|
||||
#(#attrs)*
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, #(#derive_paths),*)]
|
||||
#[rustc_layout_scalar_valid_range_end(#max)]
|
||||
#[rustc_pass_by_value]
|
||||
#[cfg_attr(#gate_rustc_only_cfg, rustc_layout_scalar_valid_range_end(#max))]
|
||||
#[cfg_attr(#gate_rustc_only_cfg, rustc_pass_by_value)]
|
||||
#vis struct #name {
|
||||
private: u32,
|
||||
}
|
||||
|
|
@ -75,7 +75,7 @@ impl<'a> DescriptionCtx<'a> {
|
|||
// We shouldn't really be having unification failures with ReVar
|
||||
// and ReBound though.
|
||||
//
|
||||
// FIXME(@lcnr): figure out why we `ReBound` have to handle `ReBound`
|
||||
// FIXME(@lcnr): figure out why we have to handle `ReBound`
|
||||
// here, this feels somewhat off.
|
||||
ty::ReVar(_) | ty::ReBound(..) | ty::ReErased => {
|
||||
(alt_span, "revar", format!("{region:?}"))
|
||||
|
|
|
|||
|
|
@ -65,8 +65,15 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
|
||||
/// Forks the inference context, creating a new inference context with the same inference
|
||||
/// variables in the same state. This can be used to "branch off" many tests from the same
|
||||
/// common state. Used in coherence.
|
||||
/// common state.
|
||||
pub fn fork(&self) -> Self {
|
||||
self.fork_with_intercrate(self.intercrate)
|
||||
}
|
||||
|
||||
/// Forks the inference context, creating a new inference context with the same inference
|
||||
/// variables in the same state, except possibly changing the intercrate mode. This can be
|
||||
/// used to "branch off" many tests from the same common state. Used in negative coherence.
|
||||
pub fn fork_with_intercrate(&self, intercrate: bool) -> Self {
|
||||
Self {
|
||||
tcx: self.tcx,
|
||||
defining_use_anchor: self.defining_use_anchor,
|
||||
|
|
@ -81,7 +88,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
tainted_by_errors: self.tainted_by_errors.clone(),
|
||||
err_count_on_creation: self.err_count_on_creation,
|
||||
universe: self.universe.clone(),
|
||||
intercrate: self.intercrate,
|
||||
intercrate,
|
||||
next_trait_solver: self.next_trait_solver,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -860,7 +860,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
self.suggest_boxing_for_return_impl_trait(
|
||||
err,
|
||||
ret_sp,
|
||||
prior_arms.iter().chain(std::iter::once(&arm_span)).map(|s| *s),
|
||||
prior_arms.iter().chain(std::iter::once(&arm_span)).copied(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -2351,6 +2351,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
|
||||
let labeled_user_string = match bound_kind {
|
||||
GenericKind::Param(ref p) => format!("the parameter type `{p}`"),
|
||||
GenericKind::Placeholder(ref p) => format!("the placeholder type `{p:?}`"),
|
||||
GenericKind::Alias(ref p) => match p.kind(self.tcx) {
|
||||
ty::AliasKind::Projection | ty::AliasKind::Inherent => {
|
||||
format!("the associated type `{p}`")
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use smallvec::{smallvec, SmallVec};
|
|||
pub enum Component<'tcx> {
|
||||
Region(ty::Region<'tcx>),
|
||||
Param(ty::ParamTy),
|
||||
Placeholder(ty::PlaceholderType),
|
||||
UnresolvedInferenceVariable(ty::InferTy),
|
||||
|
||||
// Projections like `T::Foo` are tricky because a constraint like
|
||||
|
|
@ -120,6 +121,10 @@ fn compute_components<'tcx>(
|
|||
out.push(Component::Param(p));
|
||||
}
|
||||
|
||||
ty::Placeholder(p) => {
|
||||
out.push(Component::Placeholder(p));
|
||||
}
|
||||
|
||||
// For projections, we prefer to generate an obligation like
|
||||
// `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
|
||||
// regionck more ways to prove that it holds. However,
|
||||
|
|
@ -176,7 +181,6 @@ fn compute_components<'tcx>(
|
|||
ty::Tuple(..) | // ...
|
||||
ty::FnPtr(_) | // OutlivesFunction (*)
|
||||
ty::Dynamic(..) | // OutlivesObject, OutlivesFragment (*)
|
||||
ty::Placeholder(..) |
|
||||
ty::Bound(..) |
|
||||
ty::Error(_) => {
|
||||
// (*) Function pointers and trait objects are both binders.
|
||||
|
|
|
|||
|
|
@ -243,6 +243,9 @@ where
|
|||
Component::Param(param_ty) => {
|
||||
self.param_ty_must_outlive(origin, region, *param_ty);
|
||||
}
|
||||
Component::Placeholder(placeholder_ty) => {
|
||||
self.placeholder_ty_must_outlive(origin, region, *placeholder_ty);
|
||||
}
|
||||
Component::Alias(alias_ty) => self.alias_ty_must_outlive(origin, region, *alias_ty),
|
||||
Component::EscapingAlias(subcomponents) => {
|
||||
self.components_must_outlive(origin, &subcomponents, region, category);
|
||||
|
|
@ -267,10 +270,28 @@ where
|
|||
region: ty::Region<'tcx>,
|
||||
param_ty: ty::ParamTy,
|
||||
) {
|
||||
let verify_bound = self.verify_bound.param_bound(param_ty);
|
||||
let verify_bound = self.verify_bound.param_or_placeholder_bound(param_ty.to_ty(self.tcx));
|
||||
self.delegate.push_verify(origin, GenericKind::Param(param_ty), region, verify_bound);
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn placeholder_ty_must_outlive(
|
||||
&mut self,
|
||||
origin: infer::SubregionOrigin<'tcx>,
|
||||
region: ty::Region<'tcx>,
|
||||
placeholder_ty: ty::PlaceholderType,
|
||||
) {
|
||||
let verify_bound = self
|
||||
.verify_bound
|
||||
.param_or_placeholder_bound(Ty::new_placeholder(self.tcx, placeholder_ty));
|
||||
self.delegate.push_verify(
|
||||
origin,
|
||||
GenericKind::Placeholder(placeholder_ty),
|
||||
region,
|
||||
verify_bound,
|
||||
);
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn alias_ty_must_outlive(
|
||||
&mut self,
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue