Auto merge of #3182 - RalfJung:rustup, r=RalfJung

Rustup
This commit is contained in:
bors 2023-11-21 17:26:55 +00:00
commit 49261152b5
1172 changed files with 22473 additions and 16500 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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[&param_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,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2023-11-10"
channel = "nightly-2023-11-16"
components = ["rust-src", "rustc-dev", "llvm-tools"]

View file

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

View file

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

View file

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

View file

@ -383,6 +383,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
args,
ret_place,
target,
source_info.span,
);
return;
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2023-10-21"
channel = "nightly-2023-11-17"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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(|&param| 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;
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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 = []

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

View file

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

View file

@ -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:?}"))

View file

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

View file

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

View file

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

View file

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